Skip to content

fix: align Deep Agents with Relay 0.6 - #107

Merged
rapids-bot[bot] merged 3 commits into
NVIDIA:mainfrom
bbednarski9:fix/relay-v06-dependency-compat
Jul 23, 2026
Merged

fix: align Deep Agents with Relay 0.6#107
rapids-bot[bot] merged 3 commits into
NVIDIA:mainfrom
bbednarski9:fix/relay-v06-dependency-compat

Conversation

@bbednarski9

@bbednarski9 bbednarski9 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • update the Deep Agents adapter from deepagents 0.5.x to the 0.6.x line
  • require NeMo Relay 0.6 for Fabric Relay extras
  • refresh repository and adapter lockfiles to select compatible versions
  • translate the existing flat Fabric ATOF config into Relay 0.6 v2 file and stream sink objects at the Python API boundary
  • refresh Python attribution metadata for the resolved dependency versions

Why

The previous constraints could not resolve Relay 0.6 together with Deep Agents 0.6. Once those constraints were corrected, CI exposed a second incompatibility at runtime: Relay 0.6 removed the flat AtofConfig(output_directory=..., filename=..., mode=..., endpoints=...) constructor in favor of an observability v2 model containing typed sinks.

Without adapting that boundary, every Deep Agents invocation with Relay enabled failed before the agent ran:

TypeError: AtofConfig.__init__() got an unexpected keyword argument "output_directory"

ATOF compatibility behavior

This PR currently preserves the existing Fabric configuration shape and translates it into Relay 0.6 objects internally:

  • output_directory, filename, and mode become an AtofFileSinkConfig
  • each entry in endpoints becomes an AtofStreamSinkConfig
  • stream settings such as headers, header_env, timeout_millis, field_name_policy, and name are preserved
  • already-structured v2 sinks entries are also accepted
  • the Relay Python API receives observability config version 2

This keeps the dependency upgrade independently usable without forcing a coordinated configuration migration.

However, Fabric has not had its first release yet. This may be the least expensive point to make the Relay 0.6 v2 sink model the canonical typed Fabric configuration and remove the legacy flat representation instead of establishing a compatibility contract that must later be deprecated. Reviewer guidance on that choice is requested below.

Impact

  • nemo-relay: 0.5.0 -> 0.6.0
  • deepagents: 0.5.9 -> 0.6.12
  • compatible LangChain/LangGraph transitive versions are refreshed
  • existing ATOF file and endpoint settings are preserved as Relay 0.6 file and stream sinks

This PR does not change Hermes behavior, add a Relay CLI/gateway process, or install the separately distributed nemo-relay CLI executable.

Validation

  • tests/adapters/test_adapaters_common_utils.py and tests/adapters/test_deepagents.py: 79 passed
  • tests/e2e/test_deepagents.py::test_deepagents_persistent_host_with_relay_and_mock_model: passed
  • full CI Python matrix: passed on Python 3.11 through 3.14 across Linux, macOS, and Windows
  • Rust tests and wheel builds: passed
  • pre-commit, DCO, Branch Checker, and CodeRabbit: passed
  • UV_CACHE_DIR=/private/tmp/nemo-fabric-pr0-uv-cache uv lock --check
  • git diff --check

Summary by CodeRabbit

  • New Features

    • Added support for the v2 observability configuration format.
    • Improved ATOF configuration handling with file and stream sink support.
    • Preserved compatibility with existing endpoint-based configurations.
  • Bug Fixes

    • Corrected translation of legacy observability settings into the newer sink-based format.
  • Tests

    • Added coverage for migrating endpoint-based ATOF configurations and preserving their settings.

Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Updated Relay dependency constraints and attribution versions, and changed observability translation to emit version 2 with sink-based ATOF configuration. Legacy ATOF fields and endpoints are converted into file and stream sinks, with tests covering the transformed output.

Changes

Relay v2 migration

Layer / File(s) Summary
Update compatible dependency ranges
adapters/deepagents/pyproject.toml, pyproject.toml, ATTRIBUTIONS-Python.md
Raised the minimum deepagents and nemo-relay versions and updated the corresponding locked-package attribution entries.
Translate ATOF configuration to sinks
adapters/common/src/nemo_fabric_adapters/common/utils.py, tests/adapters/test_adapaters_common_utils.py
relay_api_plugin_config now emits observability version 2, while ATOF translation builds file and stream sinks from explicit or legacy configuration fields and endpoints; tests verify the resulting structure.

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

Sequence Diagram(s)

sequenceDiagram
  participant PluginConfig
  participant relay_api_plugin_config
  participant _relay_api_atof_config
  participant ObservabilityConfig
  PluginConfig->>relay_api_plugin_config: Provide plugin configuration
  relay_api_plugin_config->>_relay_api_atof_config: Translate ATOF configuration
  _relay_api_atof_config->>_relay_api_atof_config: Build file and stream sinks
  _relay_api_atof_config-->>relay_api_plugin_config: Return sink-based AtofConfig
  relay_api_plugin_config->>ObservabilityConfig: Emit version 2 configuration
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the changes and validation, but it does not follow the required template sections or include the issue/checkbox section. Rewrite it to use the template headings: Overview, Where should the reviewer start?, Related Issues, and include the two confirmation checkboxes.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title matches Conventional Commits and accurately summarizes the Relay 0.6/Deep Agents dependency update.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Signed-off-by: Bryan Bednarski <bbednarski@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.

Actionable comments posted: 2

🤖 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 `@adapters/common/src/nemo_fabric_adapters/common/utils.py`:
- Around line 338-364: Update the sink-processing loop in the ATOF configuration
parser to handle every unrecognized or malformed entry in value["sinks"] through
the existing unsupported-value policy, or raise a validation error when no such
policy applies. Do not silently continue for non-dict entries or unknown sink
types; preserve the existing handling for valid "file" and "stream" sinks.

In `@tests/adapters/test_adapaters_common_utils.py`:
- Around line 380-383: Update
test_relay_api_plugin_config_translates_flat_atof_to_relay_v06_sinks to set
TOKEN through os.environ instead of monkeypatch.setenv, relying on the autouse
restore_environ_fixture for cleanup. Remove the now-unused monkeypatch parameter
if no other code in the test uses it.
🪄 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: 2ea9a6a9-8f0b-4d85-9a10-28979418e484

📥 Commits

Reviewing files that changed from the base of the PR and between 4ea64c3 and 98c92b9.

📒 Files selected for processing (3)
  • ATTRIBUTIONS-Python.md
  • 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. (17)
  • GitHub Check: Test (Python 3.12, windows-amd64)
  • GitHub Check: Test (Python 3.12, linux-amd64)
  • GitHub Check: Test (Python 3.14, windows-amd64)
  • GitHub Check: Test (Python 3.11, windows-amd64)
  • GitHub Check: Test (Python 3.14, linux-amd64)
  • GitHub Check: Test (Python 3.13, linux-amd64)
  • GitHub Check: Test (Python 3.11, linux-amd64)
  • GitHub Check: Test (Python 3.11, linux-arm64)
  • GitHub Check: Test (Python 3.12, macos-arm64)
  • GitHub Check: Test (Python 3.13, windows-amd64)
  • GitHub Check: Test (Python 3.14, macos-arm64)
  • GitHub Check: Test (Python 3.12, linux-arm64)
  • GitHub Check: Test (Python 3.13, macos-arm64)
  • GitHub Check: Test (Python 3.14, linux-arm64)
  • GitHub Check: Test (Python 3.13, linux-arm64)
  • GitHub Check: Test (Python 3.11, macos-arm64)
  • GitHub Check: Pre-commit
🧰 Additional context used
📓 Path-based instructions (21)
**/*.{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/adapters/test_adapaters_common_utils.py
  • adapters/common/src/nemo_fabric_adapters/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:

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

Files:

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

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

Files:

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

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

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

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

  • ATTRIBUTIONS-Python.md
**/*.{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:

  • ATTRIBUTIONS-Python.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:

  • ATTRIBUTIONS-Python.md
**/ATTRIBUTIONS-*.md

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

Regenerate and include changed ATTRIBUTIONS-*.md files.

Files:

  • ATTRIBUTIONS-Python.md
**/*.{md,mdx}

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

**/*.{md,mdx}: Use the full product name NVIDIA NeMo Fabric on its first usage, typically in the title or H1; use NeMo Fabric thereafter.
Use fabric by itself only when referring to the CLI tool, and surround those references with backticks.
Capitalize NVIDIA correctly in public documentation.
Format commands, code elements, expressions, file names, paths, and filenames as inline code where needed.
Use title case consistently for headings in technical documentation.
Introduce code blocks, tables, and lists with complete lead-in sentences.
Use descriptive anchor text instead of raw URLs or generic link text such as here.
Prefer active voice, present tense, short sentences, and plain English.
Use consistent terminology for the same concept throughout a document.
Write procedures as imperative, parallel, easy-to-scan steps, and split long sequences into smaller tasks.
Use after instead of once when expressing temporal sequence.
Use can instead of may when the intended meaning is 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.
Introduce examples' code blocks with full sentences and ensure examples match current APIs and build commands.

For documentation-site changes, run just docs to regenerate Python and Rust API references and validate Fern configuration.

Files:

  • ATTRIBUTIONS-Python.md
**/{README.md,*.md,*.mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update relevant SDK, API, adapter, example, integration, and embedded documentation when public behavior or the corresponding surface changes.

Files:

  • ATTRIBUTIONS-Python.md
**/*.{html,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

HTML and Markdown files must use the specified HTML comment form for SPDX license headers.

Files:

  • ATTRIBUTIONS-Python.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:

  • ATTRIBUTIONS-Python.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:

  • adapters/common/src/nemo_fabric_adapters/common/utils.py
🪛 ast-grep (0.44.1)
tests/adapters/test_adapaters_common_utils.py

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

(hardcoded-tmp-file)


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

(hardcoded-tmp-file)

🪛 Ruff (0.15.21)
tests/adapters/test_adapaters_common_utils.py

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

(S108)


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

(S108)

adapters/common/src/nemo_fabric_adapters/common/utils.py

[warning] 359-359: Use list.extend to create a transformed list

(PERF401)

🔇 Additional comments (3)
ATTRIBUTIONS-Python.md (1)

1804-1813: LGTM!

Also applies to: 4763-4766, 5463-5466

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

288-291: LGTM!

tests/adapters/test_adapaters_common_utils.py (1)

384-436: LGTM!

Comment on lines +338 to +364
from nemo_relay.observability import AtofFileSinkConfig
from nemo_relay.observability import AtofStreamSinkConfig

sinks: list[AtofFileSinkConfig | AtofStreamSinkConfig] = []
has_explicit_file_sink = False
for sink in value.get("sinks") or []:
if not isinstance(sink, dict):
continue
if sink.get("type") == "file":
has_explicit_file_sink = True
sinks.append(_relay_api_atof_file_sink_config(sink))
elif sink.get("type") == "stream":
sinks.append(_relay_api_atof_stream_sink_config(sink))

if not has_explicit_file_sink and any(
key in value for key in ("output_directory", "filename", "mode")
):
sinks.append(_relay_api_atof_file_sink_config(value))

for endpoint in value.get("endpoints") or []:
if isinstance(endpoint, dict):
sinks.append(_relay_api_atof_stream_sink_config(endpoint))

return AtofConfig(
enabled=bool(value.get("enabled", False)),
sinks=sinks,
)

@coderabbitai coderabbitai Bot Jul 23, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm nemo-relay's Python bindings for AtofConfig/sinks and whether
# unknown sink "type" values are expected to be rejected during validation.
python - <<'EOF'
import inspect
try:
    from nemo_relay.observability import AtofConfig, AtofFileSinkConfig, AtofStreamSinkConfig
    print(inspect.signature(AtofConfig))
    print(inspect.signature(AtofFileSinkConfig))
    print(inspect.signature(AtofStreamSinkConfig))
except ImportError as e:
    print("nemo_relay not installed in this sandbox:", e)
EOF

Repository: NVIDIA/NeMo-Fabric

Length of output: 227


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant converter and nearby validation helpers.
FILE='adapters/common/src/nemo_fabric_adapters/common/utils.py'
grep -n -A80 -B40 'def .*relay_api.*atof\|def relay_api_plugin_config\|ConfigPolicy\.unsupported_value\|sinks' "$FILE" | sed -n '1,240p'

printf '\n--- tests mentioning Atof or sink kinds ---\n'
rg -n "Atof|unsupported_value|sink.*type|output_directory|filename|mode|endpoints" adapters/common -g '*test*' -g '*py'

printf '\n--- definitions of ConfigPolicy ---\n'
rg -n "class ConfigPolicy|unsupported_value" adapters/common -g '*.py'

Repository: NVIDIA/NeMo-Fabric

Length of output: 18155


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Narrow read of the converter to understand control flow and error handling.
FILE='adapters/common/src/nemo_fabric_adapters/common/utils.py'
python3 - <<'PY'
from pathlib import Path
path = Path('adapters/common/src/nemo_fabric_adapters/common/utils.py')
lines = path.read_text().splitlines()
for start in (300, 330, 360):
    end = min(len(lines), start + 80)
    print(f"\n### lines {start}-{end}")
    for i in range(start, end):
        print(f"{i+1:4d}: {lines[i]}")
PY

Repository: NVIDIA/NeMo-Fabric

Length of output: 10461


Handle unknown ATOF sink types
Unrecognized or malformed sinks[] entries are skipped here, so a typo or future sink kind disappears without any diagnostic. Route them through the same unsupported-value policy or raise an error instead of dropping them.

🧰 Tools
🪛 Ruff (0.15.21)

[warning] 359-359: Use list.extend to create a transformed list

(PERF401)

🤖 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 `@adapters/common/src/nemo_fabric_adapters/common/utils.py` around lines 338 -
364, Update the sink-processing loop in the ATOF configuration parser to handle
every unrecognized or malformed entry in value["sinks"] through the existing
unsupported-value policy, or raise a validation error when no such policy
applies. Do not silently continue for non-dict entries or unknown sink types;
preserve the existing handling for valid "file" and "stream" sinks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

only relevant with the compatibility parser. See if we need this after getting peer feedback

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@bbednarski9, agreed. This is only relevant if the flat/v1 compatibility parser remains. I’ll leave the finding open pending the configuration decision; if the parser is removed in favor of typed v2 sinks, it no longer applies.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Follow-up opened in #114. Since NeMo Fabric has not been released, I removed the compatibility parser instead of adding more handling around it. Relay 0.6 v2 file and stream sinks are now the canonical Rust/Python config, and the adapters consume that sink shape directly. This finding therefore no longer applies.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment thread tests/adapters/test_adapaters_common_utils.py Outdated
@bbednarski9

Copy link
Copy Markdown
Contributor Author

Reviewer input requested on the ATOF configuration boundary:

Relay 0.6 now models ATOF destinations as typed file and stream sinks. This PR currently keeps the older flat Fabric fields and translates them internally so the dependency upgrade remains backward compatible.

Because Fabric is still pre-first-release, should we instead make the Relay 0.6 v2 sink structure the canonical typed Fabric configuration now and remove the flat representation before it becomes a public compatibility contract?

My current lean is to migrate now unless we already have external configurations that we explicitly want to preserve. I can either:

  1. keep this compatibility translation and handle the typed-config migration in a follow-up PR, including a deprecation path; or
  2. update this PR to use typed v2 sinks end-to-end and remove the legacy flat shape before review/merge.

Please weigh in on which contract you want Fabric to establish.

Signed-off-by: Bryan Bednarski <bbednarski@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)

380-433: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the remaining promised translation paths.

This test verifies only legacy flat ATOF input. Add, or point to existing tests for, structured v2 sink preservation and invalid configuration/error handling so the migration contract is not protected by a single happy-path case.

🤖 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 380 - 433, Extend
coverage around
test_relay_api_plugin_config_translates_flat_atof_to_relay_v06_sinks by adding
tests for preserving structured v2 ATOF sinks and rejecting invalid
configurations with the expected error. Reuse existing fixtures or helpers where
available, and keep the current legacy flat-input assertions unchanged.

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 380-433: Extend coverage around
test_relay_api_plugin_config_translates_flat_atof_to_relay_v06_sinks by adding
tests for preserving structured v2 ATOF sinks and rejecting invalid
configurations with the expected error. Reuse existing fixtures or helpers where
available, and keep the current legacy flat-input assertions unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 3f22f8b2-6f94-4ed2-b1f3-dfbf4622a3c6

📥 Commits

Reviewing files that changed from the base of the PR and between 98c92b9 and 4602cf6.

📒 Files selected for processing (1)
  • tests/adapters/test_adapaters_common_utils.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{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/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:

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

Files:

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

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

Files:

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

**/*.{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/adapters/test_adapaters_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
**/*.{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/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 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/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:

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

  • 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
🪛 Ruff (0.15.21)
tests/adapters/test_adapaters_common_utils.py

[error] 381-381: Possible hardcoded password assigned to: "TOKEN"

(S105)

🔇 Additional comments (1)
tests/adapters/test_adapaters_common_utils.py (1)

5-5: LGTM!

@bbednarski9
bbednarski9 marked this pull request as ready for review July 23, 2026 20:45
@bbednarski9
bbednarski9 requested review from a team as code owners July 23, 2026 20:45
@AnuradhaKaruppiah

Copy link
Copy Markdown
Collaborator

/merge

@rapids-bot
rapids-bot Bot merged commit e0c8d87 into NVIDIA:main Jul 23, 2026
26 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jul 24, 2026
2 tasks
rapids-bot Bot pushed a commit that referenced this pull request Jul 24, 2026
#### Overview

Make the Relay 0.6 observability v2 sink model canonical in NeMo Fabric:

- replace flat ATOF file fields and endpoint models with typed `file` and `stream` sinks in Rust and Python
- pass v2 sink configuration directly to the Relay API and CLI paths
- normalize and collect artifacts only for local file sinks, leaving stream sinks untouched
- update schemas, generated API references, examples, integration guidance, and tests

Validation:

- `cargo test --workspace --locked`
- focused Python SDK, adapter, schema-alignment, and API-reference tests
- Ruff and `cargo fmt` checks
- Fern config and strict broken-link checks

#### Where should the reviewer start?

Start with `python/src/nemo_fabric/models.py` and `crates/fabric-core/src/config.rs` for the public sink contract, then `adapters/common/src/nemo_fabric_adapters/common/utils.py` for the direct Relay 0.6 adapter path.

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

- Relates to #107

- [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**
  * Relay observability now defaults to version 2.
  * ATOF output configuration is now sink-based via `sinks`, supporting multiple **file** and **stream** sinks (HTTP POST, WebSocket, NDJSON).
* **Documentation**
  * Updated SDK guidance, API references, examples, and notebooks to use the new sink-based Relay ATOF models.
* **Bug Fixes**
  * Artifact collection is tightened to pull ATOF/ATIF artifacts only from enabled, correctly configured sink output directories (and skips when outputs are missing).
* **Tests**
  * Expanded/updated coverage for sink-based v2 behavior and artifact collection rules.

Authors:
  - Anuradha Karuppiah (https://github.com/AnuradhaKaruppiah)

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

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants