Skip to content

fix: require Relay 0.7 for coding-agent gateways - #180

Closed
AjayThorve wants to merge 2 commits into
NVIDIA:release/0.1from
AjayThorve:fix/relay-0-7-cli-compatibility
Closed

fix: require Relay 0.7 for coding-agent gateways#180
AjayThorve wants to merge 2 commits into
NVIDIA:release/0.1from
AjayThorve:fix/relay-0-7-cli-compatibility

Conversation

@AjayThorve

@AjayThorve AjayThorve commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Overview

This hotfix moves the external NeMo Relay CLI contract used by the Codex and
Claude adapters from >=0.6.0,<0.7.0 to >=0.7.0,<0.8.0.

Relay 0.6 reproduced the Platform 0.4 blocker: successful Codex turns returned
ATOF before the corresponding ATIF was visible to Fabric, so relay_atif and
the Evaluator trace descriptor were omitted. The released Relay 0.7.0 binary
returned both artifacts in the same live test and under parallel persistent
runtime load. Requiring 0.7 removes the known-bad runtime combination without
adding a polling loop or process-global session state.

Relay 0.7 also requires observability configuration version 3. Fabric now
renders its stable public configuration model into that contract at gateway
launch:

  • ATOF and ATIF sections are preserved.
  • Version-2 OpenTelemetry and OpenInference sections become typed version-3
    OpenTelemetry endpoints.
  • Missing required endpoints and removed version-2 projection controls fail
    before Relay starts instead of being silently discarded.
  • The caller-owned configuration is not mutated.

The separately imported nemo-relay Python dependency used by Deep Agents and
Hermes remains unchanged; this PR only changes the external CLI contract owned
by the coding-agent adapters.

Breaking change: Relay-enabled Codex and Claude runtimes must install the
external NeMo Relay 0.7.x CLI.

Where should the reviewer start?

Start with
adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py for the CLI
version boundary, then
adapters/common/src/nemo_fabric_adapters/common/utils.py for the isolated
version-2 to version-3 configuration translation. The regression assertions
are in tests/adapters/test_adapters_common_relay_gateway.py and
tests/adapters/test_adapaters_common_utils.py.

Validation:

  • uv run --no-sync pytest -q — 576 passed, 15 skipped.
  • uv run --no-sync pre-commit run --all-files — passed.
  • just docs — passed; only the expected unauthenticated Fern redirect warning.
  • Real Relay 0.7.0 Codex SDK E2E — passed for one-shot and two-turn persistent
    execution.
  • Parallel live probe — six independent one-shot runtimes and four independent
    persistent runtimes with two turns each all returned ATOF and ATIF with the
    correct per-session marker.
  • The Relay 0.7.0 gateway accepted Fabric-generated ATOF file and HTTP stream
    sinks, ATIF, full OpenTelemetry, and OpenInference configuration.

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

  • Relates to the NeMo Platform 0.4 Codex ATIF release blocker.

  • 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

    • Added support for NeMo Relay CLI 0.7.x with observability configuration version 3.
    • Automatically converts compatible observability settings to the new format while preserving existing telemetry options.
    • Added validation for required endpoints and unsupported configuration fields, with clear errors for invalid settings.
  • Documentation

    • Updated integration guides, SDK documentation, and examples to reflect Relay 0.7.x requirements and configuration behavior.

Signed-off-by: Ajay Thorve <athorve@nvidia.com>
@AjayThorve
AjayThorve requested review from a team as code owners August 6, 2026 07:17
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The PR updates Relay CLI support from 0.6.x to 0.7.x. It reports observability contract version 3 and converts version-2 plugin configuration into version-3 endpoint configuration with validation.

Changes

Relay 0.7 migration

Layer / File(s) Summary
Relay CLI contract and compatibility references
adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py, tests/adapters/test_adapters_common_relay_gateway.py, adapters/*/README.md, docs/integrations/harness/*, docs/sdk/python.mdx, examples/*/README.md
The supported CLI range is now >=0.7.0,<0.8.0. The reported observability version is now 3. Documentation and examples use the new range.
Version 2 to version 3 configuration conversion
adapters/common/src/nemo_fabric_adapters/common/utils.py, tests/adapters/test_adapaters_common_utils.py
write_relay_configs converts legacy observability sections to version-3 OTLP endpoints, validates required endpoints and removed fields, deep-copies input configuration, and defaults to version 3.
Adapter and end-to-end Relay fixtures
tests/adapters/test_claude_adapter.py, tests/adapters/test_codex_adapter.py, tests/e2e/test_claude.py
Claude, Codex, and end-to-end fixtures now report Relay 0.7.0 and observability version 3.

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

Sequence Diagram(s)

sequenceDiagram
  participant Adapter
  participant write_relay_configs
  participant _relay_plugin_config_for_version
  participant RelayConfigFile
  Adapter->>write_relay_configs: request Relay configuration version 3
  write_relay_configs->>_relay_plugin_config_for_version: convert plugin configuration
  _relay_plugin_config_for_version-->>write_relay_configs: return validated endpoint configuration
  write_relay_configs->>RelayConfigFile: write serialized configuration
Loading

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Title check ❌ Error The title follows Conventional Commits format but omits the required ! suffix for the breaking Relay CLI contract change. Change the title to fix!: require Relay 0.7 for coding-agent gateways.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
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.
Description check ✅ Passed The description includes the required overview, reviewer guidance, related issue entry, completed checklists, and validation details.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions

github-actions Bot commented Aug 6, 2026

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/adapters/test_adapaters_common_utils.py (1)

760-769: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Replace the hardcoded /tmp paths with tmp_path to clear the Ruff S108 error.

Ruff reports S108 at Line 769 and ast-grep reports hardcoded-tmp-file. These values are inert test data, so the fix costs one line each and keeps the lint gate green.

🧹 Proposed fix
                     "atof": {
                         "enabled": True,
                         "sinks": [
                             {
                                 "type": "file",
-                                "output_directory": "/tmp/atof",
+                                "output_directory": str(tmp_path / "atof"),
                             }
                         ],
                     },
-                    "atif": {"enabled": True, "output_directory": "/tmp/atif"},
+                    "atif": {
+                        "enabled": True,
+                        "output_directory": str(tmp_path / "atif"),
+                    },
🤖 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/adapters/test_adapaters_common_utils.py` around lines 760 - 769,
Replace the hardcoded “/tmp/atof” and “/tmp/atif” values in the test
configuration with paths derived from the pytest tmp_path fixture, preserving
the existing directory names and configuration structure.

Source: Linters/SAST tools

🤖 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 `@docs/sdk/python.mdx`:
- Line 509: Update the sentence near “translates its public observability model”
to use “NeMo Relay” consistently instead of “Relay’s,” and replace the vague “At
launch” qualifier with wording that identifies the specific launch or timeframe.
- Around line 507-512: Update the NeMo Relay CLI installation section in the
install guide to explicitly require versions from 0.7.0 inclusive through below
0.8.0, matching the range documented near the Claude and Codex streaming
requirements in the SDK guide.

In `@tests/adapters/test_adapaters_common_utils.py`:
- Around line 827-868: Parametrize the two rejection cases in the test module
using shared plugin configuration and expected ValueError-message inputs, while
preserving each case’s distinct error match. Add a third parametrized case
covering an unsupported observability version (a value other than 3) through
_relay_plugin_config_for_version, and add coverage for write_relay_configs using
its default observability version of 3.

---

Outside diff comments:
In `@tests/adapters/test_adapaters_common_utils.py`:
- Around line 760-769: Replace the hardcoded “/tmp/atof” and “/tmp/atif” values
in the test configuration with paths derived from the pytest tmp_path fixture,
preserving the existing directory names and configuration structure.
🪄 Autofix

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: 6100a717-eb7e-45ab-8d45-0e8699a2c03c

📥 Commits

Reviewing files that changed from the base of the PR and between 1175227 and 61528b8.

📒 Files selected for processing (15)
  • adapters/claude/README.md
  • adapters/codex/README.md
  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • docs/integrations/harness/claude.mdx
  • docs/integrations/harness/codex.mdx
  • docs/sdk/python.mdx
  • examples/code_review_agent/README.md
  • examples/harbor/README.md
  • examples/harbor/swebench/README.md
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.py
  • tests/adapters/test_codex_adapter.py
  • tests/e2e/test_claude.py
📜 Review details
⏰ Context from checks skipped due to timeout. (18)
  • GitHub Check: Preview docs
  • GitHub Check: Test (Python 3.13, macos-arm64)
  • 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.14, macos-arm64)
  • GitHub Check: Test (Python 3.12, linux-amd64)
  • GitHub Check: Test (Python 3.13, linux-amd64)
  • GitHub Check: Test (Python 3.14, linux-amd64)
  • GitHub Check: Test (Python 3.11, windows-amd64)
  • GitHub Check: Test (Python 3.11, macos-arm64)
  • GitHub Check: Test (Python 3.13, linux-arm64)
  • GitHub Check: Test (Python 3.13, windows-amd64)
  • GitHub Check: Test (Python 3.14, linux-arm64)
  • GitHub Check: Test (Python 3.11, linux-amd64)
  • GitHub Check: Test (Python 3.11, linux-arm64)
  • GitHub Check: Test (Python 3.12, linux-arm64)
  • GitHub Check: Pre-commit
🧰 Additional context used
📓 Path-based instructions (33)
**/*.{md,rst}

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

Update documentation and examples in the same branch as the public API change.

Files:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • adapters/claude/README.md
  • adapters/codex/README.md
  • examples/harbor/swebench/README.md
{README.md,docs/**/*.{md,mdx,yml},examples/**/*.{md,mdx,yml}}

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

Keep package names, repository references, and build commands current in documentation and examples.

Files:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • docs/integrations/harness/codex.mdx
  • docs/integrations/harness/claude.mdx
  • docs/sdk/python.mdx
  • examples/harbor/swebench/README.md
{docs/**/*.{md,mdx,yml},examples/**/*.{md,mdx,yml}}

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

Update relevant getting-started, reference, adapter, and example documentation when the corresponding examples or adapters change.

Files:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • docs/integrations/harness/codex.mdx
  • docs/integrations/harness/claude.mdx
  • docs/sdk/python.mdx
  • examples/harbor/swebench/README.md
**/*

📄 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:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • adapters/claude/README.md
  • docs/integrations/harness/codex.mdx
  • docs/integrations/harness/claude.mdx
  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • docs/sdk/python.mdx
  • tests/e2e/test_claude.py
  • adapters/codex/README.md
  • tests/adapters/test_codex_adapter.py
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
  • examples/harbor/swebench/README.md
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.py
**/*.{md,mdx,rst}

📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)

**/*.{md,mdx,rst}: For NeMo Fabric documentation, verify technical claims against the current repository, public API, or documented command before reviewing style.
Always spell NVIDIA in all caps; do not use Nvidia, nvidia, or NV.
Format commands, code elements, expressions, package names, file names, and paths as inline code.
Use descriptive link text; avoid raw URLs and weak anchors such as here or read more.
Use title case consistently for technical documentation headings.
Introduce code blocks, lists, tables, and images with complete sentences.
Write procedures as imperative, parallel steps; split long procedures into smaller tasks.
Prefer active voice, present tense, short sentences, contractions, and plain English while preserving necessary technical precision.
Use can for possibility and reserve may for permission.
Use after for temporal relationships instead of once, and prefer refer to over see when directing readers to another resource.
Avoid culture-specific idioms, unnecessary Latinisms, jokes, and marketing exaggeration in technical documentation.
Spell out months in body text, avoid ordinal dates, and use clear time zones.
Spell out whole numbers from zero through nine unless they are technical values, parameters, versions, or UI values; use numerals for 10 or greater and commas in thousands.
Do not add trademark symbols to learning-oriented documentation unless the source, platform, or legal guidance explicitly requires them.
Do not replace precise technical terms with simpler words when doing so would lose precision.
Do not flag passive voice when the actor is unknown or the action is the important part.
Do not rewrite API names, package names, command flags, or code literals for style.

**/*.{md,mdx,rst}: Use consistent title case for technical-document headings and table headers; avoid quotation marks, ampersands, and exclamation marks in headings, while preserving official product, event, research, and whitepaper title ...

Files:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • adapters/claude/README.md
  • docs/integrations/harness/codex.mdx
  • docs/integrations/harness/claude.mdx
  • docs/sdk/python.mdx
  • adapters/codex/README.md
  • examples/harbor/swebench/README.md
**/*.{md,rst,txt,adoc}

📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-language-mechanics.md)

**/*.{md,rst,txt,adoc}: For technical documentation, use professional, active, conversational, engaging, precise, and plain-English prose. Prefer active voice, present tense, short sentences, and scannable paragraphs. Avoid casual or imprecise language, swearing, threats, insults, jokes, puns, culture-specific idioms, marketing exaggeration, and unsupported third-party comparisons.
Use can for possibility and reserve may for permission; use after for temporal order; use refer to for cross-references; prefer short direct sentences and specific verbs; avoid unnecessary please in technical documentation.
Prefer active voice when the actor matters. Passive voice is acceptable when the actor is unknown or irrelevant, when the action or result is the focus, or in programmer documentation.
Use natural contractions in conversational technical prose, but do not force them in formal legal copy, API references, or generated text.
Prefer simpler English over Latinisms: use for example or such as instead of e.g., and so on instead of etc., that is instead of i.e., compared to instead of vs., and by, through, or using instead of via. Use industry-standard terms such as in silico, in vitro, and in vivo when appropriate, and italicize them in running text.
Use that without commas for essential clauses, and which with commas for nonessential clauses.
Format dates and times clearly: spell out months in body text; use forms such as June 12, 2025; avoid numeric or ordinal dates; capitalize days; use 12-hour time when appropriate; include a space before a.m. or p.m.; use ET and PT for needed time zones; avoid 24/7; and prefer from 12:30 to 1:00 p.m. for prose ranges.
Format numbers consistently: spell out zero through nine in body text, use numerals for 10 or greater and for technical values, use commas in thousands, do not begin a sentence with a numeral, spell out ordinals, and use numerals consistently within a category wh...

Files:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • adapters/claude/README.md
  • adapters/codex/README.md
  • examples/harbor/swebench/README.md
examples/{README.md,**/*}

📄 CodeRabbit inference engine (AGENTS.md)

Update examples documentation and relevant examples when public behavior, the package, or supported bindings change.

Files:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • examples/harbor/swebench/README.md
**/*.{md,mdx,yml,py,rs,sh}

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

Keep documentation aligned with current NeMo Fabric behavior, repository layout, entry points, commands, package names, APIs, bindings, and support claims.

Files:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • adapters/claude/README.md
  • docs/integrations/harness/codex.mdx
  • docs/integrations/harness/claude.mdx
  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • docs/sdk/python.mdx
  • tests/e2e/test_claude.py
  • adapters/codex/README.md
  • tests/adapters/test_codex_adapter.py
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
  • examples/harbor/swebench/README.md
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.py
**/*.{md,mdx}

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

**/*.{md,mdx}: Use the full product name NVIDIA NeMo Fabric on first use, typically in the title and H1; use NeMo Fabric thereafter. Use fabric alone only for the CLI tool and surround it with backticks.
Treat incorrect or stale commands, package names, paths, APIs, support claims, procedures, examples, terminology, or public behavior documentation as blocking issues.
Capitalize NVIDIA correctly and format code, commands, paths, and filenames as inline code where needed.
Use title case for technical-documentation headings.
Introduce code blocks, tables, and lists with complete lead-in sentences; ensure examples match current APIs and build commands.
Use descriptive anchor text, avoid raw URLs and generic labels such as here, and use repository-relative .mdx paths for links within docs/.
Prefer active voice, present tense, short sentences, plain English, consistent terminology, and imperative, parallel, scannable procedures.
Use after instead of once when expressing temporal sequence, and use can rather than may when describing possibility rather than permission.
Avoid ambiguous numeric dates and ordinal dates in body text.
For learning-oriented documentation, do not force trademark symbols unless the source document explicitly requires them.
When reporting documentation-review findings, lead with Must fix, Should fix, and Nice to have categories; include file path, line reference, current problem, rationale, and a concrete rewrite or direction.

Files:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • adapters/claude/README.md
  • docs/integrations/harness/codex.mdx
  • docs/integrations/harness/claude.mdx
  • docs/sdk/python.mdx
  • adapters/codex/README.md
  • examples/harbor/swebench/README.md
**/*.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update relevant SDK, API reference, adapter, example, integration, and support documentation when the corresponding public surface changes.

Files:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • adapters/claude/README.md
  • adapters/codex/README.md
  • examples/harbor/swebench/README.md
**/*.{html,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

HTML and Markdown files must use the specified SPDX HTML-comment header.

Files:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • adapters/claude/README.md
  • adapters/codex/README.md
  • examples/harbor/swebench/README.md
{adapters/**,examples/**}

⚙️ CodeRabbit configuration file

{adapters/**,examples/**}: Review adapter and example changes for command correctness, config/schema consistency, artifact handling, and compatibility with the public NeMo Fabric contracts.

Files:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • adapters/claude/README.md
  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • adapters/codex/README.md
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • examples/harbor/swebench/README.md
{*.md,**/*.md,**/*.mdx,**/*.ipynb}

⚙️ CodeRabbit configuration file

{*.md,**/*.md,**/*.mdx,**/*.ipynb}: Enforce the product name in user-facing prose: use "NVIDIA NeMo Fabric" on first use and "NeMo Fabric" thereafter. Flag standalone capitalized "Fabric" when it refers to the product. Do not flag the lowercase fabric CLI command, package/import/crate names, code identifiers, API symbols, configuration keys, file paths, or unrelated generic uses of the word.

Files:

  • examples/harbor/README.md
  • examples/code_review_agent/README.md
  • adapters/claude/README.md
  • docs/integrations/harness/codex.mdx
  • docs/integrations/harness/claude.mdx
  • docs/sdk/python.mdx
  • adapters/codex/README.md
  • examples/harbor/swebench/README.md
adapters/*/README.md

📄 CodeRabbit inference engine (AGENTS.md)

Update adapter integration READMEs when public behavior, examples, or supported bindings change.

Document adapter installation, supported configuration, harness-only settings, credentials, lifecycle, telemetry, artifacts, limitations, and focused test commands. Include a canonical typed SDK example and, when required, a canonical harness-native YAML fixture.

Files:

  • adapters/claude/README.md
  • adapters/codex/README.md
adapters/**/*

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

Place repository adapters under adapters/<name>, define their install extra and packaged descriptor, select the matching harness.resolution strategy, and document repository or base_dir descriptor discovery.

Files:

  • adapters/claude/README.md
  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • adapters/codex/README.md
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
**/*.mdx

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

In MDX files, use JSX comment delimiters ({/* and */}) for top-of-file comments, including SPDX headers; do not use HTML comments.

**/*.mdx: For documentation site changes, run just docs to regenerate Python and Rust API references and validate Fern configuration.
MDX files must use the specified JSX-comment SPDX header.

Files:

  • docs/integrations/harness/codex.mdx
  • docs/integrations/harness/claude.mdx
  • docs/sdk/python.mdx
docs/**/*.{md,mdx,yml}

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

Run just docs when the documentation site changes.

Update user-facing Fern documentation, including docs/index.yml, when public behavior, the package, examples, or supported bindings change.

Files:

  • docs/integrations/harness/codex.mdx
  • docs/integrations/harness/claude.mdx
  • docs/sdk/python.mdx
docs/**/*.mdx

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

docs/**/*.mdx: Use source-relative links with the target .mdx extension for links between files under docs/; do not use Fern site-root paths.
Use {/* ... */} delimiters for top-of-file MDX SPDX comments, not HTML comment delimiters.

Files:

  • docs/integrations/harness/codex.mdx
  • docs/integrations/harness/claude.mdx
  • docs/sdk/python.mdx
{docs/**,README.md,AGENTS.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,AGENTS.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency with generated schemas.
For links between files under docs/, require paths relative to the source file with the target file's .mdx extension so they work in both Fern builds and repository browsers. Flag Fern site-root links such as NeMo Fabric overview; use the repository-relative equivalent, such as NeMo Fabric overview.

Files:

  • docs/integrations/harness/codex.mdx
  • docs/integrations/harness/claude.mdx
  • docs/sdk/python.mdx
**/*.{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:

  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • tests/e2e/test_claude.py
  • tests/adapters/test_codex_adapter.py
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.py
**/*.{rs,py}

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

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

Use snake_case for functions and variables; use PascalCase for Rust types and Python classes.

Files:

  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • tests/e2e/test_claude.py
  • tests/adapters/test_codex_adapter.py
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.py
**/*.{py,pyi}

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

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

In Python SDK, adapters, examples, and tests, follow the existing style, use type annotations for public APIs, and keep native binding declarations synchronized with their Rust implementations.

Files:

  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • tests/e2e/test_claude.py
  • tests/adapters/test_codex_adapter.py
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.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.

Files:

  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • tests/e2e/test_claude.py
  • tests/adapters/test_codex_adapter.py
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.py
**/*.{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.

Public contract changes must keep native Python binding declarations synchronized with their Rust implementations.

Files:

  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • tests/e2e/test_claude.py
  • tests/adapters/test_codex_adapter.py
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.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:

  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • tests/e2e/test_claude.py
  • tests/adapters/test_codex_adapter.py
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.py
**/*.{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:

  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • tests/e2e/test_claude.py
  • tests/adapters/test_codex_adapter.py
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.py
adapters/**/*.{py,js,ts,java,go,rs}

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

adapters/**/*.{py,js,ts,java,go,rs}: Use the existing Fabric python or process runner and normalized request/result contracts. Reuse adapters/common/ only when its contract fits; do not add a runner or abstraction for one adapter.
For adapters consuming normalized configuration or runtime context, use the complete Fabric invocation and treat config, capability_plan, telemetry_plan, and runtime_context as authoritative. Reserve harness.settings for harness-specific behavior.
Apply configuration precedence in this order: normalized config; Fabric-resolved plans and runtime context; harness-specific settings; descriptor and adapter defaults. Reject conflicting duplicate declarations or unsupported behavior with actionable field-specific errors; never silently drop configuration.
Run dependency and authentication preflight before invoking the harness. Declare fixed dependencies in descriptor requirements, validate versions, hooks, and credentials, and never expose credential values in output, errors, events, logs, or fixtures.
Forward only required system variables, selected credential variables, telemetry variables, and documented harness-specific environment; never forward or log unrelated environment values.
Run one local adapter host per Fabric runtime for ordered startinvoke*stop. Emit one JSON lifecycle response per request on stdout and diagnostics on stderr; treat early exit as a host crash.
Return harness-level invoke failures in a successful lifecycle response with response: null, failed: true, and structured error containing code, message, retryable, and optional metadata.
Do not emit NeMo Relay stream records on adapter stdout. Relay records are sent out of band through the SDK-owned NDJSON ATOF endpoint; the adapter must return exactly one terminal lifecycle response.
Scope workspace, generated configuration, state, sessions, and artifacts to the resolved runtime context. Write artifacts only within the resolved r...

Files:

  • adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
docs/sdk/python.mdx

📄 CodeRabbit inference engine (AGENTS.md)

Keep the Python/Rust binding contract current when the public API changes.

Files:

  • docs/sdk/python.mdx
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/e2e/test_claude.py
  • tests/adapters/test_codex_adapter.py
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.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 by the async runner.
Do not add -> None return type annotations to test functions.
When mocking a class, use unittest.mock.MagicMock or 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.
If a fixture is needed in multiple test files, define it once in conftest.py rather than repeating it.
Define fixtures using @pytest.fixture(name="<fixture_name>"[, scope="<scope>"]) and a <fixture_name>_fixture function; 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 returned value is unused or it returns no value.
Avoid defensive programming in tests; access expected values directly so missing data raises a clear failure, such as using results["data"] instead of results.get("data").
When adapter installation metadata changes, packaging metadata tests must directly assert that the root project depends unconditionally on the exact-version nemo-fabric-runtime distribution.
Packaging metadata tests must verify that each root harness extra delegates to the matching version of the leaf adapter's harness extra.
Packaging metadata tests must verify that bare leaf dependencies remain adapter-owned and that the root adapter-tests dependency group installs each leaf through its harness extra.
Packaging metadata tests must verify that every leaf provides full; only adapters importing NeMo Relay Python APIs provide relay, while adapters using an external Relay executable have full equal to harness.

Files:

  • tests/e2e/test_claude.py
  • tests/adapters/test_codex_adapter.py
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.py
{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/e2e/test_claude.py
  • tests/adapters/test_codex_adapter.py
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.py
tests/adapters/**/*.py

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

tests/adapters/**/*.py: If an adapter or integration changes, run its focused tests.
For adapter behavior changes, run focused adapter tests under tests/adapters, then run just test-python.

Files:

  • tests/adapters/test_codex_adapter.py
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.py
tests/adapters/test_*.py

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

tests/adapters/test_*.py: Add focused tests for descriptor shape and exact capabilities, positive normalized-surface mappings, rejection of unsupported values and unenforceable policies, result normalization without secret leakage, one-shot execution, continuation, runtime isolation, and the packaged subprocess entry point.
Provide a credential-free fixture covering plan, doctor, and run; keep credential-dependent live-harness tests opt-in while retaining a deterministic CI end-to-end path.

Files:

  • tests/adapters/test_codex_adapter.py
  • tests/adapters/test_adapaters_common_utils.py
  • tests/adapters/test_adapters_common_relay_gateway.py
  • tests/adapters/test_claude_adapter.py
🪛 ast-grep (0.45.0)
tests/adapters/test_adapaters_common_utils.py

[info] 768-768: Do not hardcode temporary file or directory names
Context: "/tmp/atif"
Note: [CWE-377] Insecure Temporary File.

(hardcoded-tmp-file)

🪛 Ruff (0.16.1)
adapters/common/src/nemo_fabric_adapters/common/utils.py

[warning] 404-407: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 412-415: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 431-434: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 448-451: Avoid specifying long messages outside the exception class

(TRY003)


[warning] 465-467: Prefer TypeError exception for invalid type

(TRY004)


[warning] 465-467: Avoid specifying long messages outside the exception class

(TRY003)

tests/adapters/test_adapaters_common_utils.py

[error] 769-769: Probable insecure usage of temporary file or directory: "/tmp/atif"

(S108)

🔇 Additional comments (19)
tests/adapters/test_adapters_common_relay_gateway.py (2)

72-73: LGTM!

Also applies to: 76-76, 86-86


49-60: 🎯 Functional Correctness

Define Relay prerelease compatibility.

relay_cli_contract ignores prerelease identifiers, so 0.7.0-alpha.20260805 is accepted as (0, 7, 0). If >=0.7.0,<0.8.0 follows SemVer, reject this fixture; otherwise document that the compatibility check uses numeric components only.

adapters/claude/README.md (1)

123-124: LGTM!

adapters/codex/README.md (1)

148-149: LGTM!

docs/integrations/harness/claude.mdx (1)

173-174: LGTM!

docs/integrations/harness/codex.mdx (1)

206-207: LGTM!

examples/harbor/README.md (1)

76-76: LGTM!

adapters/common/src/nemo_fabric_adapters/common/relay_gateway.py (1)

23-24: 🗄️ Data Integrity & Integration

No shared-contract change is required. relay_cli_contract is used only by Claude and Codex, which both require the external NeMo Relay 0.7.x CLI. Hermes and Deep Agents use the separate Python package path.

docs/sdk/python.mdx (1)

278-278: LGTM!

examples/code_review_agent/README.md (1)

77-77: LGTM!

adapters/common/src/nemo_fabric_adapters/common/utils.py (4)

8-8: LGTM!


427-451: 🩺 Stability & Availability

No change needed. relay_cli_contract rejects Relay CLI versions outside >=0.7.0,<0.8.0 and returns observability_version=3; repository callers cannot pass version 2 to this function.

			> Likely an incorrect or invalid review comment.

486-490: 🎯 Functional Correctness

No test change is needed

The parametrized fixtures contain no observability component, and all production call sites pass observability_version explicitly. The round-trip assertion remains valid.

			> Likely an incorrect or invalid review comment.

396-424: 🗄️ Data Integrity & Integration

Confirm the disabled empty-endpoint representation.

NeMo Relay 0.7 uses this version-3 endpoint schema. Confirm that opentelemetry = { enabled = false, endpoints = [] } is accepted when all legacy exporters are disabled, rather than omitting endpoints.

tests/adapters/test_adapaters_common_utils.py (1)

750-750: LGTM!

Also applies to: 790-824

tests/adapters/test_claude_adapter.py (1)

331-331: LGTM!

Also applies to: 407-407

tests/adapters/test_codex_adapter.py (1)

815-815: LGTM!

Also applies to: 843-843

tests/e2e/test_claude.py (1)

50-50: LGTM!

examples/harbor/swebench/README.md (1)

34-38: 🗄️ Data Integrity & Integration

Keep the exact 0.7.0 pin. The stable release exists, and install.sh accepts this version format.

			> Likely an incorrect or invalid review comment.

Comment thread docs/sdk/python.mdx
Comment on lines 507 to 512
Claude and Codex streaming use the NeMo Relay `nemo-relay` gateway CLI and require a
stream-sink-capable release from `0.6.0` up to, but not including, `0.7.0`. Follow
release from `0.7.0` up to, but not including, `0.8.0`. At launch, NeMo Fabric
translates its public observability model to Relay's version 3 configuration. Follow
the [NeMo Relay CLI installation instructions](../getting-started/install.mdx#install-nemo-relay)
to provision it. Hermes Agent and Deep Agents use their in-process NeMo Relay
integrations.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Find remaining NeMo Relay 0.6 references and check the install page range.
set -euo pipefail

# Locate the install page and print its Relay section.
fd -t f 'install.mdx' docs | while IFS= read -r f; do
  echo "== $f =="
  rg -n -C 5 'nemo-relay|NEMO_RELAY_VERSION|0\.6|0\.7' "$f" || true
done

# Any lingering 0.6.x Relay CLI references across docs, examples, code, and manifests.
rg -n -C 2 '0\.6\.0|0\.6\.x|<0\.7' --glob '!**/*.lock' || true

Repository: NVIDIA/NeMo-Fabric

Length of output: 2029


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== docs/getting-started/install.mdx: Relay section =="
sed -n '126,186p' docs/getting-started/install.mdx

echo "== References to the install-page anchor =="
rg -n -C 2 'install\.mdx#install-nemo-relay|0\.7\.0|0\.8\.0|0\.6\.[0-9]+' \
  docs examples README.md --glob '!**/*.lock' || true

Repository: NVIDIA/NeMo-Fabric

Length of output: 6660


Add the NeMo Relay CLI version range to the installation guide.

docs/getting-started/install.mdx#install-nemo-relay does not state the required 0.7.0 to <0.8.0 range. Add it so the linked installation guidance matches the adapter documentation.

🤖 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 `@docs/sdk/python.mdx` around lines 507 - 512, Update the NeMo Relay CLI
installation section in the install guide to explicitly require versions from
0.7.0 inclusive through below 0.8.0, matching the range documented near the
Claude and Codex streaming requirements in the SDK guide.

Comment thread docs/sdk/python.mdx
Claude and Codex streaming use the NeMo Relay `nemo-relay` gateway CLI and require a
stream-sink-capable release from `0.6.0` up to, but not including, `0.7.0`. Follow
release from `0.7.0` up to, but not including, `0.8.0`. At launch, NeMo Fabric
translates its public observability model to Relay's version 3 configuration. Follow

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

Use NeMo Relay instead of Relay's, and replace the vague At launch qualifier.

The rest of this page uses NeMo Relay consistently. At launch does not identify which launch.

📝 Proposed wording
-release from `0.7.0` up to, but not including, `0.8.0`. At launch, NeMo Fabric
-translates its public observability model to Relay's version 3 configuration. Follow
+release from `0.7.0` up to, but not including, `0.8.0`. When it starts the gateway,
+NeMo Fabric translates its public observability model to the NeMo Relay version 3
+configuration. Follow

As per coding guidelines: "Use the same term consistently for the same concept."

🤖 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 `@docs/sdk/python.mdx` at line 509, Update the sentence near “translates its
public observability model” to use “NeMo Relay” consistently instead of
“Relay’s,” and replace the vague “At launch” qualifier with wording that
identifies the specific launch or timeframe.

Source: Coding guidelines

Comment on lines +827 to +868
def test_relay_0_7_config_requires_enabled_otlp_endpoint():
plugin_config = {
"components": [
{
"kind": "observability",
"config": {
"version": 2,
"openinference": {"enabled": True},
},
}
]
}
assert rendered == plugin_config

with pytest.raises(
ValueError,
match="version 3 requires an endpoint for enabled openinference export",
):
common_utils._relay_plugin_config_for_version(plugin_config, 3)


def test_relay_0_7_config_rejects_removed_otlp_controls():
plugin_config = {
"components": [
{
"kind": "observability",
"config": {
"version": 2,
"opentelemetry": {
"enabled": True,
"endpoint": "http://localhost:4318/v1/traces",
"mark_projection": "tool",
},
},
}
]
}

with pytest.raises(
ValueError,
match="cannot preserve opentelemetry fields: mark_projection",
):
common_utils._relay_plugin_config_for_version(plugin_config, 3)

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 | 🔵 Trivial | ⚡ Quick win

Parametrize the two rejection tests and add the missing unsupported-version case.

Both tests share one shape: a plugin configuration and an expected ValueError message. The observability_version != 3 branch at adapters/common/src/nemo_fabric_adapters/common/utils.py Line 430 has no coverage, and neither does the new default of 3 in write_relay_configs.

♻️ Proposed parametrized rewrite
-def test_relay_0_7_config_requires_enabled_otlp_endpoint():
-    plugin_config = {
-        "components": [
-            {
-                "kind": "observability",
-                "config": {
-                    "version": 2,
-                    "openinference": {"enabled": True},
-                },
-            }
-        ]
-    }
-
-    with pytest.raises(
-        ValueError,
-        match="version 3 requires an endpoint for enabled openinference export",
-    ):
-        common_utils._relay_plugin_config_for_version(plugin_config, 3)
-
-
-def test_relay_0_7_config_rejects_removed_otlp_controls():
-    plugin_config = {
-        "components": [
-            {
-                "kind": "observability",
-                "config": {
-                    "version": 2,
-                    "opentelemetry": {
-                        "enabled": True,
-                        "endpoint": "http://localhost:4318/v1/traces",
-                        "mark_projection": "tool",
-                    },
-                },
-            }
-        ]
-    }
-
-    with pytest.raises(
-        ValueError,
-        match="cannot preserve opentelemetry fields: mark_projection",
-    ):
-        common_utils._relay_plugin_config_for_version(plugin_config, 3)
+@pytest.mark.parametrize(
+    ("observability_config", "target_version", "expected_message"),
+    [
+        (
+            {"version": 2, "openinference": {"enabled": True}},
+            3,
+            "version 3 requires an endpoint for enabled openinference export",
+        ),
+        (
+            {
+                "version": 2,
+                "opentelemetry": {
+                    "enabled": True,
+                    "endpoint": "http://localhost:4318/v1/traces",
+                    "mark_projection": "tool",
+                },
+            },
+            3,
+            "cannot preserve opentelemetry fields: mark_projection",
+        ),
+        (
+            {"version": 2},
+            2,
+            "unsupported NeMo Relay observability config version 2",
+        ),
+    ],
+)
+def test_relay_0_7_config_rejects_invalid_observability_config(
+    observability_config, target_version, expected_message
+):
+    plugin_config = {
+        "components": [
+            {"kind": "observability", "config": observability_config}
+        ]
+    }
+
+    with pytest.raises(ValueError, match=expected_message):
+        common_utils._relay_plugin_config_for_version(
+            plugin_config, target_version
+        )

As per coding guidelines: "Prefer pytest.mark.parametrize over separate tests for different input types."

📝 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
def test_relay_0_7_config_requires_enabled_otlp_endpoint():
plugin_config = {
"components": [
{
"kind": "observability",
"config": {
"version": 2,
"openinference": {"enabled": True},
},
}
]
}
assert rendered == plugin_config
with pytest.raises(
ValueError,
match="version 3 requires an endpoint for enabled openinference export",
):
common_utils._relay_plugin_config_for_version(plugin_config, 3)
def test_relay_0_7_config_rejects_removed_otlp_controls():
plugin_config = {
"components": [
{
"kind": "observability",
"config": {
"version": 2,
"opentelemetry": {
"enabled": True,
"endpoint": "http://localhost:4318/v1/traces",
"mark_projection": "tool",
},
},
}
]
}
with pytest.raises(
ValueError,
match="cannot preserve opentelemetry fields: mark_projection",
):
common_utils._relay_plugin_config_for_version(plugin_config, 3)
`@pytest.mark.parametrize`(
("observability_config", "target_version", "expected_message"),
[
(
{"version": 2, "openinference": {"enabled": True}},
3,
"version 3 requires an endpoint for enabled openinference export",
),
(
{
"version": 2,
"opentelemetry": {
"enabled": True,
"endpoint": "http://localhost:4318/v1/traces",
"mark_projection": "tool",
},
},
3,
"cannot preserve opentelemetry fields: mark_projection",
),
(
{"version": 2},
2,
"unsupported NeMo Relay observability config version 2",
),
],
)
def test_relay_0_7_config_rejects_invalid_observability_config(
observability_config, target_version, expected_message
):
plugin_config = {
"components": [
{"kind": "observability", "config": observability_config}
]
}
with pytest.raises(ValueError, match=expected_message):
common_utils._relay_plugin_config_for_version(
plugin_config, target_version
)
🤖 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/adapters/test_adapaters_common_utils.py` around lines 827 - 868,
Parametrize the two rejection cases in the test module using shared plugin
configuration and expected ValueError-message inputs, while preserving each
case’s distinct error match. Add a third parametrized case covering an
unsupported observability version (a value other than 3) through
_relay_plugin_config_for_version, and add coverage for write_relay_configs using
its default observability version of 3.

Source: Coding guidelines

Signed-off-by: Ajay Thorve <athorve@nvidia.com>

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/adapters/test_adapaters_common_utils.py (1)

806-835: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Assert that the complete input configuration remains unchanged.

The test checks selected fields and the source version. A mutation to another nested field could update plugin_config and still allow the current assertions to pass.

Deep-copy plugin_config before calling write_relay_configs, then assert equality after the call.

As per path instructions: tests should cover the behavior promised by the changed API surface.

Proposed test assertion
+    original_plugin_config = copy.deepcopy(plugin_config)
+
     _, plugin_path = common_utils.write_relay_configs(
         plugin_config=plugin_config,
         observability_version=3,
     )
 
+    assert plugin_config == original_plugin_config
🤖 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/adapters/test_adapaters_common_utils.py` around lines 806 - 835, Update
the test around write_relay_configs to deep-copy plugin_config before invoking
it, then assert the original plugin_config equals that copy after the call.
Preserve the existing output assertions while adding this complete deep-equality
check to detect mutations in any nested configuration field.

Source: Path instructions

🤖 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.

Outside diff comments:
In `@tests/adapters/test_adapaters_common_utils.py`:
- Around line 806-835: Update the test around write_relay_configs to deep-copy
plugin_config before invoking it, then assert the original plugin_config equals
that copy after the call. Preserve the existing output assertions while adding
this complete deep-equality check to detect mutations in any nested
configuration field.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 13e4b1e5-8de7-4294-b1aa-4959886c719c

📥 Commits

Reviewing files that changed from the base of the PR and between 61528b8 and 4c33cbf.

📒 Files selected for processing (2)
  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
📜 Review details
⏰ Context from checks skipped due to timeout. (19)
  • GitHub Check: Preview docs
  • GitHub Check: Test (Python 3.13, linux-arm64)
  • GitHub Check: Test (Python 3.12, linux-amd64)
  • GitHub Check: Test (Python 3.11, windows-amd64)
  • GitHub Check: Test (Python 3.12, windows-amd64)
  • GitHub Check: Test (Python 3.11, linux-amd64)
  • GitHub Check: Test (Python 3.11, macos-arm64)
  • GitHub Check: Test (Python 3.13, macos-arm64)
  • GitHub Check: Test (Python 3.12, macos-arm64)
  • GitHub Check: Test (Python 3.13, linux-amd64)
  • GitHub Check: Test (Python 3.14, windows-amd64)
  • GitHub Check: Test (Python 3.14, linux-arm64)
  • GitHub Check: Test (Python 3.14, linux-amd64)
  • GitHub Check: Test (Python 3.14, macos-arm64)
  • GitHub Check: Test (Python 3.11, linux-arm64)
  • GitHub Check: Test (Python 3.13, windows-amd64)
  • GitHub Check: Test (Python 3.12, linux-arm64)
  • GitHub Check: Pre-commit
  • GitHub Check: Test (arm64)
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{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:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
**/*

📄 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:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
**/*.{rs,py}

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

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

Use snake_case for functions and variables; use PascalCase for Rust types and Python classes.

Files:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
**/*.{py,pyi}

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

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

In Python SDK, adapters, examples, and tests, follow the existing style, use type annotations for public APIs, and keep native binding declarations synchronized with their Rust implementations.

Files:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.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.

Files:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
**/*.{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.

Public contract changes must keep native Python binding declarations synchronized with their Rust implementations.

Files:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.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:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
**/*.{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:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
**/*.{md,mdx,yml,py,rs,sh}

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

Keep documentation aligned with current NeMo Fabric behavior, repository layout, entry points, commands, package names, APIs, bindings, and support claims.

Files:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
  • tests/adapters/test_adapaters_common_utils.py
adapters/**/*

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

Place repository adapters under adapters/<name>, define their install extra and packaged descriptor, select the matching harness.resolution strategy, and document repository or base_dir descriptor discovery.

Files:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
adapters/**/*.{py,js,ts,java,go,rs}

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

adapters/**/*.{py,js,ts,java,go,rs}: Use the existing Fabric python or process runner and normalized request/result contracts. Reuse adapters/common/ only when its contract fits; do not add a runner or abstraction for one adapter.
For adapters consuming normalized configuration or runtime context, use the complete Fabric invocation and treat config, capability_plan, telemetry_plan, and runtime_context as authoritative. Reserve harness.settings for harness-specific behavior.
Apply configuration precedence in this order: normalized config; Fabric-resolved plans and runtime context; harness-specific settings; descriptor and adapter defaults. Reject conflicting duplicate declarations or unsupported behavior with actionable field-specific errors; never silently drop configuration.
Run dependency and authentication preflight before invoking the harness. Declare fixed dependencies in descriptor requirements, validate versions, hooks, and credentials, and never expose credential values in output, errors, events, logs, or fixtures.
Forward only required system variables, selected credential variables, telemetry variables, and documented harness-specific environment; never forward or log unrelated environment values.
Run one local adapter host per Fabric runtime for ordered startinvoke*stop. Emit one JSON lifecycle response per request on stdout and diagnostics on stderr; treat early exit as a host crash.
Return harness-level invoke failures in a successful lifecycle response with response: null, failed: true, and structured error containing code, message, retryable, and optional metadata.
Do not emit NeMo Relay stream records on adapter stdout. Relay records are sent out of band through the SDK-owned NDJSON ATOF endpoint; the adapter must return exactly one terminal lifecycle response.
Scope workspace, generated configuration, state, sessions, and artifacts to the resolved runtime context. Write artifacts only within the resolved r...

Files:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
{adapters/**,examples/**}

⚙️ CodeRabbit configuration file

{adapters/**,examples/**}: Review adapter and example changes for command correctness, config/schema consistency, artifact handling, and compatibility with the public NeMo Fabric contracts.

Files:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
tests/adapters/**/*.py

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

tests/adapters/**/*.py: If an adapter or integration changes, run its focused tests.
For adapter behavior changes, run focused adapter tests under tests/adapters, then run just test-python.

Files:

  • tests/adapters/test_adapaters_common_utils.py
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/adapters/test_adapaters_common_utils.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 by the async runner.
Do not add -> None return type annotations to test functions.
When mocking a class, use unittest.mock.MagicMock or 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.
If a fixture is needed in multiple test files, define it once in conftest.py rather than repeating it.
Define fixtures using @pytest.fixture(name="<fixture_name>"[, scope="<scope>"]) and a <fixture_name>_fixture function; 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 returned value is unused or it returns no value.
Avoid defensive programming in tests; access expected values directly so missing data raises a clear failure, such as using results["data"] instead of results.get("data").
When adapter installation metadata changes, packaging metadata tests must directly assert that the root project depends unconditionally on the exact-version nemo-fabric-runtime distribution.
Packaging metadata tests must verify that each root harness extra delegates to the matching version of the leaf adapter's harness extra.
Packaging metadata tests must verify that bare leaf dependencies remain adapter-owned and that the root adapter-tests dependency group installs each leaf through its harness extra.
Packaging metadata tests must verify that every leaf provides full; only adapters importing NeMo Relay Python APIs provide relay, while adapters using an external Relay executable have full equal to harness.

Files:

  • tests/adapters/test_adapaters_common_utils.py
tests/adapters/test_*.py

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

tests/adapters/test_*.py: Add focused tests for descriptor shape and exact capabilities, positive normalized-surface mappings, rejection of unsupported values and unenforceable policies, result normalization without secret leakage, one-shot execution, continuation, runtime isolation, and the packaged subprocess entry point.
Provide a credential-free fixture covering plan, doctor, and run; keep credential-dependent live-harness tests opt-in while retaining a deterministic CI end-to-end path.

Files:

  • tests/adapters/test_adapaters_common_utils.py
{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/adapters/test_adapaters_common_utils.py
🔇 Additional comments (7)
tests/adapters/test_adapaters_common_utils.py (3)

801-804: 📐 Maintainability & Code Quality

Cover the changed version contract.

This test passes observability_version=3, so it does not exercise the new default. The rejection cases also need a non-3 target to exercise the guard in _relay_plugin_config_for_version.

Omit the argument for the default case. Add the unsupported-version case in the same parametrized table.

As per coding guidelines: “Prefer pytest.mark.parametrize over separate tests for different input types.”
As per path instructions: tests should cover the behavior promised by the changed API surface, including error paths.

Also applies to: 838-879

Sources: Coding guidelines, Path instructions


750-752: 🗄️ Data Integrity & Integration

Make the Relay 0.7 acceptance claim executable.

This test checks TOML values with tomllib. It does not validate the file with the external Relay executable.

The supplied context lists nemo-relay 0.6.0. The Python package and CLI are separate install surfaces. Official documentation is version-sensitive: released documentation shows observability version 2, while the version-3 migration documentation defines full and openinference endpoints. Confirm that an end-to-end test pins external Relay 0.7.x. Keep the unchanged Python dependency path separate. (github.com)

Source: MCP tools


753-800: LGTM!

adapters/common/src/nemo_fabric_adapters/common/utils.py (4)

8-8: LGTM!

Also applies to: 514-519


427-461: LGTM!

Also applies to: 465-485


492-492: 🎯 Functional Correctness

No in-repository caller requests observability version 2.

All callers use the version-3 contract returned by relay_cli_contract; no version-2 reference exists.

			> Likely an incorrect or invalid review comment.

462-464: 🎯 Functional Correctness

Keep explicit None sections as disabled exports.

opentelemetry and openinference accept null in the public schema and Python model. Treating None as absent is therefore valid behavior.

			> Likely an incorrect or invalid review comment.

@AjayThorve
AjayThorve marked this pull request as draft August 6, 2026 07:37
@AjayThorve AjayThorve closed this Aug 6, 2026
rapids-bot Bot pushed a commit that referenced this pull request Aug 7, 2026
#### Overview

Fix the Relay artifact lifecycle race for both Codex and Claude without
upgrading Relay or changing the observability schema. Fabric now waits for the
configured local ATIF exporter to finish before it snapshots relay_artifacts,
so a successful invocation cannot be returned while its trajectory is still in
Relay's asynchronous subscriber queue.

The readiness logic is shared in adapters/common. The existing
nemo-relay>=0.6.0,<0.7 contract remains unchanged, so this fix is suitable for
the release/0.1 line and supersedes the Relay 0.7 dependency-upgrade mitigation
in #180.

This branch also sets the release version to 0.1.1 across the Rust workspace,
all seven Python distributions, exact internal dependency pins, and lockfiles.

#### Details

- Snapshot cheap filesystem fingerprints (device, inode, size, and nanosecond
  mtime) for runtime-scoped ATIF files before an invocation.
- After a successful Codex or Claude turn, inspect only new or
  metadata-changed paths and return as soon as one contains a complete JSON
  object. This supports a new file, atomic replacement, overwrite, and append.
- Do not hash, read, or parse unchanged artifacts from prior turns.
- Keep JSON parsing as the readiness condition because Relay writes directly to
  the final path; file existence or timestamps do not prove the write is
  complete. Metadata selects candidates, while successful JSON parsing proves
  readiness.
- Use a hard five-second deadline instead of a fixed sleep. A timeout returns
  codex_relay_atif_timeout or claude_relay_atif_timeout and makes the persistent
  runtime unavailable, preventing a late artifact from being attributed to a
  later turn.
- Return an empty relay_artifacts list on timeout and bypass artifact rescanning
  on the later runtime-unavailable response.
- Skip the local-file wait when ATIF uses non-empty remote storage, because
  Relay does not produce a local ATIF in that mode.
- Preserve ATOF collection, streaming, persistent SDK sessions, and the
  runtime-owned Relay gateway.

Codex and Claude need this guard because both collect artifacts immediately
after an SDK terminal result while Relay hook events are dispatched
asynchronously. Hermes already flushes subscribers before collection, and Deep
Agents collects after leaving its Relay plugin context, so those adapters are
unchanged.

Runtime-scoped output directories keep parallel evaluator sessions isolated.
The wait is condition-based and normally adds only the time Relay needs to
finish the file.

#### Release packaging

- Ran just set-version 0.1.1.
- Updated Cargo and Python package versions plus exact internal 0.1.1 pins.
- Regenerated the Python lockfiles with the CI-pinned uv 0.9.22. Dependency
  versions are unchanged; the locks add newly published Relay 0.6 source and
  musllinux artifact records.
- Regenerated Python attributions; the only generated attribution change is the
  aiohttp license-file path.
- No public configuration or API contract changed.

#### Validation

- just test-python — 582 passed, 15 skipped.
- just test-rust — 68 passed.
- cargo check --workspace --locked — passed.
- cargo fmt --all -- --check — passed.
- just build-python — passed for all seven 0.1.1 distributions.
- just wheels — built all seven wheels; wheel metadata and exact internal
  0.1.1 pins were verified.
- Pre-commit on all files — passed, including Ruff, GitHub Actions lint,
  Cargo/uv lock freshness, generated attributions, and dependency-license
  checks.
- Real Relay 0.6 Codex and Claude E2E — passed one-shot artifact semantics and
  persistent two-turn streaming runtimes.
- Platform Codex and Claude matrix at p=1,3,5,10 — 80/80 total trials completed
  with isolated runtime-scoped ATIF directories, valid ATIF-v1.7 trajectories,
  non-empty steps, and zero contract failures.
- Exact final-head Platform regression at p=10 — Codex 10/10 and Claude 10/10,
  with 20 distinct runtime-scoped ATIF directories and zero failures.
- Exact final-head non-target Platform regression at p=5 — Deep Agents 5/5 and
  Hermes 5/5 against Relay 0.6, with ten distinct runtime-scoped directories,
  valid trajectories and promoted trace evidence, and zero failures.

Documentation is unchanged because public configuration and dependency
contracts are unchanged. There are no breaking changes.

#### Where should the reviewer start?

Start with
adapters/common/src/nemo_fabric_adapters/common/relay_artifacts.py, then the
calls from CodexRuntime.invoke() and ClaudeRuntime.invoke(). The focused tests
cover delayed and partial writes, unchanged-path exclusion, changed-path
detection, remote-only configuration, the hard timeout, no-rescan timeout
behavior, unusable-runtime behavior, and parallel runtime-directory isolation.

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

- Relates to #180 and the NeMo Platform 0.4 ATIF release blocker.

- [x] I confirm this contribution is my own work, or I have the right to submit it under this project's license.
- [x] I searched existing issues and open pull requests, and this does not duplicate existing work.



## Summary by CodeRabbit

* **New Features**
  * Added reliable Relay ATIF artifact tracking for supported Codex and Claude sessions.
  * Turns now wait for newly generated, valid artifacts before completing.
  * Added a five-second timeout for artifact finalization.

* **Bug Fixes**
  * Prevented stale or incomplete artifacts from being treated as finalized.
  * Improved isolation when multiple sessions await artifact generation.
  * Timed-out runtimes are marked unavailable to prevent subsequent use.
  * Artifact finalization timeouts now return clear, non-retryable errors.
  * Runtime failures now report a clear, generic error message.

Authors:
  - Ajay Thorve (https://github.com/AjayThorve)

Approvers:
  - Anuradha Karuppiah (https://github.com/AnuradhaKaruppiah)
  - David Gardner (https://github.com/dagardner-nv)

URL: #181
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