feat(hermes): use upstream Relay integration - #192
Conversation
Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughHermes now stages Relay plugin configuration, applies Relay environment values, executes turns through Hermes lifecycle APIs, correlates Fabric and legacy Hermes records, and restores runtime state during shutdown. Tests cover configuration, concurrency, MCP bridging, event metadata, and dependency compatibility. ChangesHermes Relay integration
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant HermesAdapter
participant RelayConfig
participant HermesAgent
participant FabricStreaming
HermesAdapter->>RelayConfig: Stage translated plugin TOML
HermesAdapter->>HermesAgent: Apply Relay environment values
HermesAdapter->>HermesAgent: Execute turn in worker thread
HermesAgent->>FabricStreaming: Emit Hermes turn records
FabricStreaming-->>HermesAdapter: Correlate turn records
HermesAdapter->>HermesAgent: Finalize Relay session
HermesAdapter->>RelayConfig: Restore environment and clear staged path
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
Fern docs preview: https://nvidia-preview-pull-request-192.docs.buildwithfern.com/nemo/fabric |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py`:
- Around line 438-441: Update the Hermes adapter lifecycle around invoke(), the
asyncio.to_thread(invoke_turn) call, and stop() to track the active worker task,
shield it from caller cancellation, and await its completion before closing
agent/session_db or restoring Relay environment state. Preserve one local
adapter host across ordered start → invoke* → stop operations, and add a
regression test verifying cleanup waits for a cancelled worker turn.
- Around line 146-167: Update the inline comment in
write_hermes_relay_plugin_config to reference Hermes Agent v0.19.0, or make it
version-neutral; do not alter the ATIF handling logic or dependency metadata.
In `@tests/e2e/test_hermes_e2e.py`:
- Around line 350-359: Update the turn_marks collection and assertions in the
Hermes E2E test to filter for records named "hermes.turn" with the expected
scope_category values, matching the established ATOF naming contract. Add an
explicit non-empty assertion before validating metadata so the model and
platform checks cannot vacuously pass.
🪄 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: 5678506e-42d4-4c4f-aba8-a80580f078e2
📒 Files selected for processing (6)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.pypython/src/nemo_fabric/streaming.pytests/adapters/test_hermes_adapter.pytests/e2e/test_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.py
📜 Review details
⏰ Context from checks skipped due to timeout. (16)
- GitHub Check: Preview docs
- GitHub Check: Test (Python 3.12, windows-amd64)
- GitHub Check: Test (Python 3.13, linux-amd64)
- GitHub Check: Test (Python 3.12, linux-arm64)
- GitHub Check: Test (Python 3.11, linux-amd64)
- GitHub Check: Test (Python 3.14, linux-arm64)
- GitHub Check: Test (Python 3.11, macos-arm64)
- GitHub Check: Test (Python 3.14, macos-arm64)
- GitHub Check: Test (Python 3.14, windows-amd64)
- GitHub Check: Test (Python 3.13, windows-amd64)
- GitHub Check: Test (Python 3.12, macos-arm64)
- GitHub Check: Test (Python 3.13, linux-arm64)
- GitHub Check: Test (Python 3.13, macos-arm64)
- GitHub Check: Test (Python 3.12, linux-amd64)
- GitHub Check: Test (Python 3.11, linux-arm64)
- GitHub Check: Test (Python 3.14, linux-amd64)
🧰 Additional context used
📓 Path-based instructions (18)
**/*.{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:
python/src/nemo_fabric/streaming.pytests/e2e/test_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.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 spellNVIDIAin all caps; do not useNvidia,nvidia,nVidia,nVIDIA, orNV.
Usean NVIDIAbefore a noun, because the name begins with an “en” sound.
Do not add a registered trademark symbol afterNVIDIAwhen 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 withNVIDIAon 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:
python/src/nemo_fabric/streaming.pytests/e2e/test_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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_casefor functions and variables; usePascalCasefor Rust types and Python classes.
Files:
python/src/nemo_fabric/streaming.pytests/e2e/test_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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:
python/src/nemo_fabric/streaming.pytests/e2e/test_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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 injust test-rustpass and review generated schema diffs.
For schema or public contract changes, run both language suites and review changes underschemas/and generated API references.
Files:
python/src/nemo_fabric/streaming.pytests/e2e/test_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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, thenjust test-python; rebuild withjust build-pythonwhen native code or packaging changes.Public contract changes must keep native Python binding declarations synchronized with their Rust implementations.
Files:
python/src/nemo_fabric/streaming.pytests/e2e/test_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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 inpython/pyproject.toml.
Files:
python/src/nemo_fabric/streaming.pytests/e2e/test_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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:
python/src/nemo_fabric/streaming.pytests/e2e/test_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
python/src/nemo_fabric/**/*.py
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/SKILL.md)
For Python API reference changes, update source docstrings under
python/src/nemo_fabric/instead of generated API reference files.
Files:
python/src/nemo_fabric/streaming.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:
python/src/nemo_fabric/streaming.pytests/e2e/test_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
python/src/nemo_fabric/**/*.{py,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure native extension naming and placement remain compatible with downstream consumers, including the editable maturin build producing
nemo_fabric._native.
Files:
python/src/nemo_fabric/streaming.py
python/src/nemo_fabric/**/*
⚙️ CodeRabbit configuration file
python/src/nemo_fabric/**/*: Review Python SDK changes for typed API consistency, import-time dependency neutrality, async/session behavior, and parity with the native extension.
Stubs and runtime implementations should stay aligned.
Files:
python/src/nemo_fabric/streaming.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/e2e/test_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.pytests/adapters/test_hermes_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.asyncioto tests; async tests are automatically detected by the async runner.
Do not add-> Nonereturn type annotations to test functions.
When mocking a class, useunittest.mock.MagicMockorAsyncMock, using thespecargument when necessary, rather than defining a new class.
Prefix mocked class names withmock, notfake.
Prefer pytest fixtures over helper methods.
If a fixture is needed in multiple test files, define it once inconftest.pyrather than repeating it.
Define fixtures using@pytest.fixture(name="<fixture_name>"[, scope="<scope>"])and a<fixture_name>_fixturefunction; specifyscopeonly when it is notfunction.
Preferpytest.mark.parametrizeover separate tests for different input types.
Use@pytest.mark.usefixtureswhen 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 usingresults["data"]instead ofresults.get("data").
When adapter installation metadata changes, packaging metadata tests must directly assert that the root project depends unconditionally on the exact-versionnemo-fabric-runtimedistribution.
Packaging metadata tests must verify that each root harness extra delegates to the matching version of the leaf adapter'sharnessextra.
Packaging metadata tests must verify that bare leaf dependencies remain adapter-owned and that the rootadapter-testsdependency group installs each leaf through itsharnessextra.
Packaging metadata tests must verify that every leaf providesfull; only adapters importing NeMo Relay Python APIs providerelay, while adapters using an external Relay executable havefullequal toharness.
Files:
tests/e2e/test_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.pytests/adapters/test_hermes_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_hermes_e2e.pytests/e2e/test_hermes_runtime.pytests/python/test_streaming.pytests/adapters/test_hermes_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 undertests/adapters, then runjust test-python.
Files:
tests/adapters/test_hermes_adapter.py
adapters/*/src/**/*.py
📄 CodeRabbit inference engine (.agents/skills/contribute-adapter/SKILL.md)
adapters/*/src/**/*.py: Implement adapters using the existing Fabricpythonorprocessrunner and normalized request/result contracts; do not add a runner or one-off abstraction for a single adapter.
Treat normalizedconfig, Fabric-resolved plans, andruntime_contextas authoritative; reserveharness.settingsfor adapter-wide behavior and apply precedence in the order: normalized config, plans/context, harness settings, descriptor/default values.
Reject conflicting duplicate declarations and unsupported behavior with actionable errors naming the field and supported alternatives; never silently drop configuration.
Validate dependency versions, hooks, and credentials before harness invocation, and never expose credential values in outputs, errors, events, logs, or fixtures.
Forward only required system, selected credential, telemetry, and documented harness-specific environment variables; never forward or log unrelated environment values.
Maintain one local adapter host per Fabric runtime across orderedstart→invoke*→stopoperations. Emit one JSON lifecycle response per request on stdout and diagnostics on stderr.
Return harness-level invocation failures as successful lifecycle responses containingresponse: null,failed: true, and structurederrorfields (code,message,retryable, and optionalmetadata).
Do not emit NeMo Relay stream records on adapter stdout; return exactly one terminal lifecycle response while streaming occurs through the SDK-owned out-of-band endpoint.
Scope workspace, generated configuration, state, sessions, and artifacts to the resolved runtime context, and isolate stateful adapter instances by Fabric runtime ID.
Usestartto initialize adapter-owned harness state, retain it for continuation across repeatedinvokecalls on the same runtime, and release it instop.
Files:
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.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/hermes/src/nemo_fabric_adapters/hermes/adapter.py
🧠 Learnings (2)
📚 Learning: 2026-06-28T04:03:32.877Z
Learnt from: AjayThorve
Repo: NVIDIA/NeMo-Fabric PR: 26
File: python/tests/smoke_typed_config.py:163-177
Timestamp: 2026-06-28T04:03:32.877Z
Learning: In NVIDIA NeMo Fabric Python SDK serialization of `RuntimeCapabilities` (to satisfy the “parity contract” with Rust core and the CLI), do not emit metadata keys when the corresponding metadata is absent. Instead, omit those fields entirely so the produced JSON matches the Rust/CLI output (e.g., avoid `null`, empty objects, or placeholder metadata). During review, verify the serializer/builders follow this omission rule and that Python outputs/parity tests reflect the same shape.
Applied to files:
python/src/nemo_fabric/streaming.py
📚 Learning: 2026-07-09T22:28:51.689Z
Learnt from: AjayThorve
Repo: NVIDIA/NeMo-Fabric PR: 43
File: adapters/claude-sdk/src/nemo_fabric_adapters/claude_sdk/adapter.py:164-168
Timestamp: 2026-07-09T22:28:51.689Z
Learning: In the NeMo-Fabric adapters, treat path values used in Fabric adapter configuration (including logic like `_resolve_path` in adapter.py) as config-root-relative. Do not apply `Path.expanduser()` (or otherwise apply `~`/home or shell-style expansion), because it will make the resolved paths normalize inconsistently across adapters. Also, do not rely on or add any resolution behavior that uses `harness.settings.cwd` as an override point for these adapter paths—`harness.settings.cwd` is explicitly unsupported in this adapter context.
Applied to files:
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
🪛 ast-grep (0.45.0)
tests/adapters/test_hermes_adapter.py
[info] 67-79: use jsonify instead of json.dumps for JSON output
Context: json.dumps(
{
"relay": {
"config": {
"atof": {
"enabled": True,
"sinks": [{"type": "file"}],
},
"atif": {"enabled": True},
}
}
}
)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
🪛 Ruff (0.16.1)
tests/adapters/test_hermes_adapter.py
[warning] 134-134: Avoid specifying long messages outside the exception class
(TRY003)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
[warning] 166-166: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 477-477: Too many branches (13 > 12)
(PLR0912)
[warning] 477-477: Too many statements (52 > 50)
(PLR0915)
🔇 Additional comments (8)
tests/e2e/test_hermes_e2e.py (1)
113-119: LGTM!Also applies to: 185-191, 252-252, 266-269, 327-349, 390-396
tests/e2e/test_hermes_runtime.py (1)
34-34: LGTM!Also applies to: 104-104
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py (3)
14-14: LGTM!Also applies to: 39-47
170-198: LGTM!Also applies to: 280-282, 313-331, 355-360
469-475: LGTM!tests/adapters/test_hermes_adapter.py (1)
13-15: LGTM!Also applies to: 62-156, 704-704, 785-785
python/src/nemo_fabric/streaming.py (1)
559-561: LGTM!tests/python/test_streaming.py (1)
883-901: LGTM!
Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py (2)
432-454: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftSerialize invocations for each
HermesRuntime.
asyncio.to_thread()releases the event loop while Hermes runs. A secondinvoke()can then use the same agent, session database, session ID, and conversation history at the same time. The last completion can overwrite history, and concurrentfinalize_session()calls can mix Relay artifacts.Add a per-runtime operation lock around
_invoke_hermes_turn()andfinalize_session(). Integrate it with the existing cancellation task tracking. Add a concurrent-invocation regression test.As per coding guidelines, “Maintain one local adapter host per Fabric runtime across ordered
start→invoke*→stopoperations.”🤖 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/hermes/src/nemo_fabric_adapters/hermes/adapter.py` around lines 432 - 454, Add a per-HermesRuntime operation lock that serializes the full invoke_turn sequence, including _invoke_hermes_turn and finalize_session, so concurrent invokes cannot share mutable agent, session, or conversation state. Acquire and release this lock through the existing cancellation task tracking, preserving cancellation behavior and ordered start → invoke* → stop lifecycle operations. Add a regression test that launches concurrent invocations on one runtime and verifies they execute serially.Source: Coding guidelines
317-332: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftDo not store runtime-specific Relay configuration in process-global environment variables.
Two active runtimes cannot safely own different
HERMES_NEMO_RELAY_*values. For example, runtime B snapshots runtime A’s value, and after A then B stop, B restores A’s stale plugin path instead of the original environment. This also permits one runtime to affect another runtime’s Relay configuration.
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py#L317-L332: isolate Relay configuration per runtime, such as with a dedicated process, instead of mutating sharedos.environ.adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py#L515-L523: remove restoration logic that attempts to reconstruct nested ownership of shared environment variables.As per coding guidelines, “Scope workspace, generated configuration, state, sessions, and artifacts to the resolved runtime context, and isolate stateful adapter instances by Fabric runtime ID.”
🤖 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/hermes/src/nemo_fabric_adapters/hermes/adapter.py` around lines 317 - 332, The Relay startup flow around the environment-application logic at adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py:317-332 must stop mutating process-global os.environ; isolate each runtime’s HERMES_NEMO_RELAY_* configuration through a dedicated process or equivalent runtime-scoped mechanism. Remove the nested environment restoration logic at adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py:515-523, including its ownership snapshots, and ensure Relay state remains scoped to the resolved Fabric runtime ID.Source: Coding guidelines
🤖 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/hermes/pyproject.toml`:
- Around line 37-41: Do not introduce the v0.20-dependent Hermes Agent extra
until an installable 0.20 release exists. In adapters/hermes/pyproject.toml
lines 37-41, either constrain the extra to the available 0.19.0 release and
support its behavior, or wait for v0.20; in
tests/adapters/test_adapter_package_metadata.py lines 53-54, align the expected
constraint with that same tested version, and keep uv.lock and documentation
consistent.
---
Outside diff comments:
In `@adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py`:
- Around line 432-454: Add a per-HermesRuntime operation lock that serializes
the full invoke_turn sequence, including _invoke_hermes_turn and
finalize_session, so concurrent invokes cannot share mutable agent, session, or
conversation state. Acquire and release this lock through the existing
cancellation task tracking, preserving cancellation behavior and ordered start →
invoke* → stop lifecycle operations. Add a regression test that launches
concurrent invocations on one runtime and verifies they execute serially.
- Around line 317-332: The Relay startup flow around the environment-application
logic at adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py:317-332 must
stop mutating process-global os.environ; isolate each runtime’s
HERMES_NEMO_RELAY_* configuration through a dedicated process or equivalent
runtime-scoped mechanism. Remove the nested environment restoration logic at
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py:515-523, including
its ownership snapshots, and ensure Relay state remains scoped to the resolved
Fabric runtime ID.
🪄 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: 4c1e0341-c6d6-458f-8797-fd6a48ede272
⛔ Files ignored due to path filters (2)
adapters/hermes/uv.lockis excluded by!**/*.lockuv.lockis excluded by!**/*.lock
📒 Files selected for processing (5)
adapters/common/src/nemo_fabric_adapters/common/utils.pyadapters/hermes/pyproject.tomladapters/hermes/src/nemo_fabric_adapters/hermes/adapter.pytests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_adapter.py
📜 Review details
⏰ Context from checks skipped due to timeout. (19)
- GitHub Check: Preview docs
- GitHub Check: Pre-commit
- GitHub Check: Test (arm64)
- GitHub Check: Test (Python 3.13, linux-amd64)
- GitHub Check: Test (Python 3.11, linux-amd64)
- GitHub Check: Test (Python 3.14, linux-amd64)
- GitHub Check: Test (Python 3.13, windows-amd64)
- GitHub Check: Test (Python 3.14, windows-amd64)
- GitHub Check: Test (Python 3.11, windows-amd64)
- GitHub Check: Test (Python 3.12, macos-arm64)
- GitHub Check: Test (Python 3.14, macos-arm64)
- GitHub Check: Test (Python 3.14, linux-arm64)
- GitHub Check: Test (Python 3.12, windows-amd64)
- GitHub Check: Test (Python 3.13, macos-arm64)
- GitHub Check: Test (Python 3.11, linux-arm64)
- GitHub Check: Test (Python 3.12, linux-amd64)
- GitHub Check: Test (Python 3.13, linux-arm64)
- GitHub Check: Test (Python 3.12, linux-arm64)
- GitHub Check: Test (Python 3.11, macos-arm64)
🧰 Additional context used
📓 Path-based instructions (25)
**/*
📄 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 spellNVIDIAin all caps; do not useNvidia,nvidia,nVidia,nVIDIA, orNV.
Usean NVIDIAbefore a noun, because the name begins with an “en” sound.
Do not add a registered trademark symbol afterNVIDIAwhen 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 withNVIDIAon 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/hermes/pyproject.tomltests/adapters/test_adapter_package_metadata.pyadapters/common/src/nemo_fabric_adapters/common/utils.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
For any Rust change, run
just test-rustandcargo fmt --all -- --check.For Rust core, CLI, or shared runtime semantic changes, run Rust formatting and tests, and add Python tests when behavior is exposed through the SDK.
Use Rust stable tooling; format Rust code with
cargo fmt --all, verify formatting withcargo fmt --all -- --check, and compile withcargo check --workspace --locked.
Files:
adapters/hermes/pyproject.toml
**/{Cargo.toml,Cargo.lock,pyproject.toml,package.json}
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
For new or updated dependencies, document the functional need, alternatives considered, and why the selected dependency is the narrowest fit.
Files:
adapters/hermes/pyproject.toml
**/*.{toml,lock}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If a manifest or lockfile changes, run the license-diff script against
origin/main, review transitive license changes, and run theattributions-rustandattributions-pythonpre-commit hooks.
Files:
adapters/hermes/pyproject.toml
**/*.{yml,yaml,toml,lock}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
For CI or packaging changes, use
maintain-ciormaintain-packaging, then run recipes and checks whose behavior changed.
Files:
adapters/hermes/pyproject.toml
{pyproject.toml,adapters/**/pyproject.toml}
📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)
{pyproject.toml,adapters/**/pyproject.toml}: Update the literalproject.versionin the root setuptools project and every adapterpyproject.toml.
Keep internal exact-version requirements aligned: rootnemo-fabric-* == <version>optional dependencies and each adapter'snemo-fabric-adapters-common == <version>dependency.
Files:
adapters/hermes/pyproject.toml
**/*.{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 inpython/pyproject.toml.
Files:
adapters/hermes/pyproject.tomltests/adapters/test_adapter_package_metadata.pyadapters/common/src/nemo_fabric_adapters/common/utils.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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/hermes/pyproject.tomltests/adapters/test_adapter_package_metadata.pyadapters/common/src/nemo_fabric_adapters/common/utils.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
**/*.{toml,yaml,yml,sh,bash}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
TOML, YAML, and shell files must use the specified
#SPDX copyright and Apache-2.0 license headers.
Files:
adapters/hermes/pyproject.toml
**/{Cargo.toml,pyproject.toml}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
**/{Cargo.toml,pyproject.toml}: Keep package names, dependency declarations, import paths, module names, and workspace or Python package metadata internally consistent.
Prefer the standard library, an existing dependency, or a small local implementation before adding a new direct dependency.
When multiple dependencies satisfy the requirement, prefer a maintained OSS option with clear SPDX metadata, a smaller transitive graph, and permissive licensing such as Apache-2.0, MIT, BSD, or ISC.
Files:
adapters/hermes/pyproject.toml
**/{Cargo.toml,pyproject.toml,Cargo.lock,uv.lock}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
**/{Cargo.toml,pyproject.toml,Cargo.lock,uv.lock}: For new dependencies, record the functional need, viable alternatives considered, why the selected dependency is the narrowest fit, and any unresolved licensing question.
After updating manifests or lockfiles, runuv run --no-project python scripts/licensing/license_diff.py --base-ref origin/mainand review added packages and license changes.
Keep workspace, Python package, and lockfile versions aligned wherever the packaging contract requires alignment.
Files:
adapters/hermes/pyproject.toml
adapters/*/pyproject.toml
📄 CodeRabbit inference engine (.agents/skills/contribute-adapter/SKILL.md)
adapters/*/pyproject.toml: Keep leaf adapter runtime dependencies razor-thin and adapter-owned. Do not declare the wrapped harness/SDK or dependencies already declared by its supported package; provide dependency-free fallbacks for optional libraries.
Provide every installable Python leaf adapter with aharnessextra and afullextra for package-installable integrations; provide arelayextra when importing NeMo Relay Python APIs, but not when Relay is an external executable.
For packaged harnesses, declare and document aharnessversion constraint supported by upstream contracts and test evidence; do not claim a broader range than the evidence supports.
Files:
adapters/hermes/pyproject.toml
adapters/*/{pyproject.toml,uv.lock}
📄 CodeRabbit inference engine (.agents/skills/contribute-adapter/SKILL.md)
Keep each adapter package independent and small, using Python package metadata and lock files as applicable.
Files:
adapters/hermes/pyproject.toml
{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/hermes/pyproject.tomladapters/common/src/nemo_fabric_adapters/common/utils.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
**/*.{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_adapter_package_metadata.pyadapters/common/src/nemo_fabric_adapters/common/utils.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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_casefor functions and variables; usePascalCasefor Rust types and Python classes.
Files:
tests/adapters/test_adapter_package_metadata.pyadapters/common/src/nemo_fabric_adapters/common/utils.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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:
tests/adapters/test_adapter_package_metadata.pyadapters/common/src/nemo_fabric_adapters/common/utils.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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 injust test-rustpass and review generated schema diffs.
For schema or public contract changes, run both language suites and review changes underschemas/and generated API references.
Files:
tests/adapters/test_adapter_package_metadata.pyadapters/common/src/nemo_fabric_adapters/common/utils.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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 undertests/adapters, then runjust test-python.
Files:
tests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_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, thenjust test-python; rebuild withjust build-pythonwhen native code or packaging changes.Public contract changes must keep native Python binding declarations synchronized with their Rust implementations.
Files:
tests/adapters/test_adapter_package_metadata.pyadapters/common/src/nemo_fabric_adapters/common/utils.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.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:
tests/adapters/test_adapter_package_metadata.pyadapters/common/src/nemo_fabric_adapters/common/utils.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.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_adapter_package_metadata.pytests/adapters/test_hermes_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.asyncioto tests; async tests are automatically detected by the async runner.
Do not add-> Nonereturn type annotations to test functions.
When mocking a class, useunittest.mock.MagicMockorAsyncMock, using thespecargument when necessary, rather than defining a new class.
Prefix mocked class names withmock, notfake.
Prefer pytest fixtures over helper methods.
If a fixture is needed in multiple test files, define it once inconftest.pyrather than repeating it.
Define fixtures using@pytest.fixture(name="<fixture_name>"[, scope="<scope>"])and a<fixture_name>_fixturefunction; specifyscopeonly when it is notfunction.
Preferpytest.mark.parametrizeover separate tests for different input types.
Use@pytest.mark.usefixtureswhen 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 usingresults["data"]instead ofresults.get("data").
When adapter installation metadata changes, packaging metadata tests must directly assert that the root project depends unconditionally on the exact-versionnemo-fabric-runtimedistribution.
Packaging metadata tests must verify that each root harness extra delegates to the matching version of the leaf adapter'sharnessextra.
Packaging metadata tests must verify that bare leaf dependencies remain adapter-owned and that the rootadapter-testsdependency group installs each leaf through itsharnessextra.
Packaging metadata tests must verify that every leaf providesfull; only adapters importing NeMo Relay Python APIs providerelay, while adapters using an external Relay executable havefullequal toharness.
Files:
tests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_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/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_adapter.py
adapters/*/src/**/*.py
📄 CodeRabbit inference engine (.agents/skills/contribute-adapter/SKILL.md)
adapters/*/src/**/*.py: Implement adapters using the existing Fabricpythonorprocessrunner and normalized request/result contracts; do not add a runner or one-off abstraction for a single adapter.
Treat normalizedconfig, Fabric-resolved plans, andruntime_contextas authoritative; reserveharness.settingsfor adapter-wide behavior and apply precedence in the order: normalized config, plans/context, harness settings, descriptor/default values.
Reject conflicting duplicate declarations and unsupported behavior with actionable errors naming the field and supported alternatives; never silently drop configuration.
Validate dependency versions, hooks, and credentials before harness invocation, and never expose credential values in outputs, errors, events, logs, or fixtures.
Forward only required system, selected credential, telemetry, and documented harness-specific environment variables; never forward or log unrelated environment values.
Maintain one local adapter host per Fabric runtime across orderedstart→invoke*→stopoperations. Emit one JSON lifecycle response per request on stdout and diagnostics on stderr.
Return harness-level invocation failures as successful lifecycle responses containingresponse: null,failed: true, and structurederrorfields (code,message,retryable, and optionalmetadata).
Do not emit NeMo Relay stream records on adapter stdout; return exactly one terminal lifecycle response while streaming occurs through the SDK-owned out-of-band endpoint.
Scope workspace, generated configuration, state, sessions, and artifacts to the resolved runtime context, and isolate stateful adapter instances by Fabric runtime ID.
Usestartto initialize adapter-owned harness state, retain it for continuation across repeatedinvokecalls on the same runtime, and release it instop.
Files:
adapters/common/src/nemo_fabric_adapters/common/utils.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
🧠 Learnings (1)
📚 Learning: 2026-07-09T22:28:51.689Z
Learnt from: AjayThorve
Repo: NVIDIA/NeMo-Fabric PR: 43
File: adapters/claude-sdk/src/nemo_fabric_adapters/claude_sdk/adapter.py:164-168
Timestamp: 2026-07-09T22:28:51.689Z
Learning: In the NeMo-Fabric adapters, treat path values used in Fabric adapter configuration (including logic like `_resolve_path` in adapter.py) as config-root-relative. Do not apply `Path.expanduser()` (or otherwise apply `~`/home or shell-style expansion), because it will make the resolved paths normalize inconsistently across adapters. Also, do not rely on or add any resolution behavior that uses `harness.settings.cwd` as an override point for these adapter paths—`harness.settings.cwd` is explicitly unsupported in this adapter context.
Applied to files:
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
🪛 ast-grep (0.45.0)
tests/adapters/test_hermes_adapter.py
[info] 118-135: use jsonify instead of json.dumps for JSON output
Context: json.dumps(
{
"relay": {
"config": {
"opentelemetry": {
"enabled": True,
"endpoint": "https://otel.example/v1/traces",
"service_name": "fabric",
},
"openinference": {
"enabled": True,
"endpoint": "https://openinference.example/v1/traces",
"service_name": "fabric",
},
}
}
}
)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
🪛 Ruff (0.16.1)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
[warning] 189-190: Use a single if statement instead of nested if statements
(SIM102)
🔇 Additional comments (3)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py (1)
157-195: LGTM!tests/adapters/test_hermes_adapter.py (1)
100-110: LGTM!Also applies to: 113-168
adapters/common/src/nemo_fabric_adapters/common/utils.py (1)
223-224: LGTM!Also applies to: 414-414
Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py (3)
333-343: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftIsolate ownership of the process Relay environment.
If two Hermes runtimes share a process, their environment snapshots interleave. If runtime A starts, runtime B starts, A stops, and B stops, B restores A's staged path after A has stopped. A later runtime can then load the stale Relay configuration.
Use a process-wide environment owner manager, or reject concurrent Hermes runtimes in one process. Restore the original baseline only after the last owner stops. Add an overlapping-runtime regression test.
As per coding guidelines, “Scope workspace, generated configuration, state, sessions, and artifacts to the resolved runtime context, and isolate stateful adapter instances by Fabric runtime ID.”
Also applies to: 526-534
🤖 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/hermes/src/nemo_fabric_adapters/hermes/adapter.py` around lines 333 - 343, Update the Relay environment lifecycle around the adapter’s startup and shutdown methods to prevent overlapping Hermes runtimes from interleaving snapshots and restorations. Introduce a process-wide ownership mechanism keyed by the resolved Fabric runtime ID, or reject concurrent runtimes; ensure the original environment baseline is restored only when the final owner stops, while each runtime’s applied configuration remains isolated. Add a regression test covering A starts, B starts, A stops, and B stops, verifying no stale Relay configuration remains.Source: Coding guidelines
443-459: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winFinalize Relay when the Hermes turn fails.
If
_invoke_hermes_turn()raises,finalize_session()does not run. Move finalization into afinallyblock when Relay is enabled, preserve the original turn error if finalization also fails, and add a regression test for this failure path.🤖 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/hermes/src/nemo_fabric_adapters/hermes/adapter.py` around lines 443 - 459, Update the turn execution flow around _invoke_hermes_turn so finalize_session runs in a finally block whenever _relay_plugin_config is enabled, including when the Hermes turn raises. Preserve the original turn exception if finalization also fails, and add a regression test covering this failure path.
493-507: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftIsolate Hermes runtime state and finalize failed turns.
HermesRuntime.start()mutates process-global environment variables, butstop()restores only Relay variables. A later runtime can inherit another runtime’sHOME,HERMES_HOME, or plugin path. Scope or serialize this state by runtime ID._invoke_hermes_turn()propagates exceptions. Therefore,finalize_session()does not run and the adapter does not return the required failed lifecycle response. Finalize infinally, normalize the exception, and add failed-turn coverage.🤖 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/hermes/src/nemo_fabric_adapters/hermes/adapter.py` around lines 493 - 507, Isolate process-global environment state in HermesRuntime.start/stop by scoping or serializing it per runtime ID, including HOME, HERMES_HOME, and plugin paths, and restore the matching state during stop. Update _invoke_hermes_turn() to always call finalize_session() in a finally path, normalize propagated exceptions into the failed-turn lifecycle response, and add coverage for failed turns.
🤖 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/hermes/pyproject.toml`:
- Around line 37-41: Pin nemo-relay to ==0.7.2 in both Hermes extras in
adapters/hermes/pyproject.toml, update the expected package metadata in
tests/adapters/test_adapter_package_metadata.py (lines 53-54), and regenerate
uv.lock so all resolved Relay versions and metadata match 0.7.2.
---
Outside diff comments:
In `@adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py`:
- Around line 333-343: Update the Relay environment lifecycle around the
adapter’s startup and shutdown methods to prevent overlapping Hermes runtimes
from interleaving snapshots and restorations. Introduce a process-wide ownership
mechanism keyed by the resolved Fabric runtime ID, or reject concurrent
runtimes; ensure the original environment baseline is restored only when the
final owner stops, while each runtime’s applied configuration remains isolated.
Add a regression test covering A starts, B starts, A stops, and B stops,
verifying no stale Relay configuration remains.
- Around line 443-459: Update the turn execution flow around _invoke_hermes_turn
so finalize_session runs in a finally block whenever _relay_plugin_config is
enabled, including when the Hermes turn raises. Preserve the original turn
exception if finalization also fails, and add a regression test covering this
failure path.
- Around line 493-507: Isolate process-global environment state in
HermesRuntime.start/stop by scoping or serializing it per runtime ID, including
HOME, HERMES_HOME, and plugin paths, and restore the matching state during stop.
Update _invoke_hermes_turn() to always call finalize_session() in a finally
path, normalize propagated exceptions into the failed-turn lifecycle response,
and add coverage for failed turns.
🪄 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: dd62e1b7-fa83-4259-89bb-a549987ac4f3
⛔ Files ignored due to path filters (2)
adapters/hermes/uv.lockis excluded by!**/*.lockuv.lockis excluded by!**/*.lock
📒 Files selected for processing (4)
adapters/hermes/pyproject.tomladapters/hermes/src/nemo_fabric_adapters/hermes/adapter.pytests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_adapter.py
📜 Review details
⏰ Context from checks skipped due to timeout. (18)
- GitHub Check: Preview docs
- GitHub Check: Pre-commit
- GitHub Check: Test (Python 3.14, linux-amd64)
- GitHub Check: Test (Python 3.14, windows-amd64)
- GitHub Check: Test (Python 3.11, windows-amd64)
- GitHub Check: Test (Python 3.13, windows-amd64)
- GitHub Check: Test (Python 3.13, macos-arm64)
- GitHub Check: Test (Python 3.12, windows-amd64)
- GitHub Check: Test (Python 3.12, linux-arm64)
- GitHub Check: Test (Python 3.12, macos-arm64)
- GitHub Check: Test (Python 3.13, linux-arm64)
- GitHub Check: Test (Python 3.14, macos-arm64)
- GitHub Check: Test (Python 3.11, linux-amd64)
- GitHub Check: Test (Python 3.11, macos-arm64)
- GitHub Check: Test (Python 3.12, linux-amd64)
- GitHub Check: Test (Python 3.11, linux-arm64)
- GitHub Check: Test (Python 3.13, linux-amd64)
- GitHub Check: Test (Python 3.14, linux-arm64)
🧰 Additional context used
📓 Path-based instructions (25)
**/*
📄 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 spellNVIDIAin all caps; do not useNvidia,nvidia,nVidia,nVIDIA, orNV.
Usean NVIDIAbefore a noun, because the name begins with an “en” sound.
Do not add a registered trademark symbol afterNVIDIAwhen 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 withNVIDIAon 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/hermes/pyproject.tomltests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
For any Rust change, run
just test-rustandcargo fmt --all -- --check.For Rust core, CLI, or shared runtime semantic changes, run Rust formatting and tests, and add Python tests when behavior is exposed through the SDK.
Use Rust stable tooling; format Rust code with
cargo fmt --all, verify formatting withcargo fmt --all -- --check, and compile withcargo check --workspace --locked.
Files:
adapters/hermes/pyproject.toml
**/{Cargo.toml,Cargo.lock,pyproject.toml,package.json}
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
For new or updated dependencies, document the functional need, alternatives considered, and why the selected dependency is the narrowest fit.
Files:
adapters/hermes/pyproject.toml
**/*.{toml,lock}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If a manifest or lockfile changes, run the license-diff script against
origin/main, review transitive license changes, and run theattributions-rustandattributions-pythonpre-commit hooks.
Files:
adapters/hermes/pyproject.toml
**/*.{yml,yaml,toml,lock}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
For CI or packaging changes, use
maintain-ciormaintain-packaging, then run recipes and checks whose behavior changed.
Files:
adapters/hermes/pyproject.toml
{pyproject.toml,adapters/**/pyproject.toml}
📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)
{pyproject.toml,adapters/**/pyproject.toml}: Update the literalproject.versionin the root setuptools project and every adapterpyproject.toml.
Keep internal exact-version requirements aligned: rootnemo-fabric-* == <version>optional dependencies and each adapter'snemo-fabric-adapters-common == <version>dependency.
Files:
adapters/hermes/pyproject.toml
**/*.{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 inpython/pyproject.toml.
Files:
adapters/hermes/pyproject.tomltests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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/hermes/pyproject.tomltests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
**/*.{toml,yaml,yml,sh,bash}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
TOML, YAML, and shell files must use the specified
#SPDX copyright and Apache-2.0 license headers.
Files:
adapters/hermes/pyproject.toml
**/{Cargo.toml,pyproject.toml}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
**/{Cargo.toml,pyproject.toml}: Keep package names, dependency declarations, import paths, module names, and workspace or Python package metadata internally consistent.
Prefer the standard library, an existing dependency, or a small local implementation before adding a new direct dependency.
When multiple dependencies satisfy the requirement, prefer a maintained OSS option with clear SPDX metadata, a smaller transitive graph, and permissive licensing such as Apache-2.0, MIT, BSD, or ISC.
Files:
adapters/hermes/pyproject.toml
**/{Cargo.toml,pyproject.toml,Cargo.lock,uv.lock}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
**/{Cargo.toml,pyproject.toml,Cargo.lock,uv.lock}: For new dependencies, record the functional need, viable alternatives considered, why the selected dependency is the narrowest fit, and any unresolved licensing question.
After updating manifests or lockfiles, runuv run --no-project python scripts/licensing/license_diff.py --base-ref origin/mainand review added packages and license changes.
Keep workspace, Python package, and lockfile versions aligned wherever the packaging contract requires alignment.
Files:
adapters/hermes/pyproject.toml
adapters/*/pyproject.toml
📄 CodeRabbit inference engine (.agents/skills/contribute-adapter/SKILL.md)
adapters/*/pyproject.toml: Keep leaf adapter runtime dependencies razor-thin and adapter-owned. Do not declare the wrapped harness/SDK or dependencies already declared by its supported package; provide dependency-free fallbacks for optional libraries.
Provide every installable Python leaf adapter with aharnessextra and afullextra for package-installable integrations; provide arelayextra when importing NeMo Relay Python APIs, but not when Relay is an external executable.
For packaged harnesses, declare and document aharnessversion constraint supported by upstream contracts and test evidence; do not claim a broader range than the evidence supports.
Files:
adapters/hermes/pyproject.toml
adapters/*/{pyproject.toml,uv.lock}
📄 CodeRabbit inference engine (.agents/skills/contribute-adapter/SKILL.md)
Keep each adapter package independent and small, using Python package metadata and lock files as applicable.
Files:
adapters/hermes/pyproject.toml
{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/hermes/pyproject.tomladapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
**/*.{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_adapter_package_metadata.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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_casefor functions and variables; usePascalCasefor Rust types and Python classes.
Files:
tests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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:
tests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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 injust test-rustpass and review generated schema diffs.
For schema or public contract changes, run both language suites and review changes underschemas/and generated API references.
Files:
tests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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 undertests/adapters, then runjust test-python.
Files:
tests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_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, thenjust test-python; rebuild withjust build-pythonwhen native code or packaging changes.Public contract changes must keep native Python binding declarations synchronized with their Rust implementations.
Files:
tests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.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:
tests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_adapter.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.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_adapter_package_metadata.pytests/adapters/test_hermes_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.asyncioto tests; async tests are automatically detected by the async runner.
Do not add-> Nonereturn type annotations to test functions.
When mocking a class, useunittest.mock.MagicMockorAsyncMock, using thespecargument when necessary, rather than defining a new class.
Prefix mocked class names withmock, notfake.
Prefer pytest fixtures over helper methods.
If a fixture is needed in multiple test files, define it once inconftest.pyrather than repeating it.
Define fixtures using@pytest.fixture(name="<fixture_name>"[, scope="<scope>"])and a<fixture_name>_fixturefunction; specifyscopeonly when it is notfunction.
Preferpytest.mark.parametrizeover separate tests for different input types.
Use@pytest.mark.usefixtureswhen 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 usingresults["data"]instead ofresults.get("data").
When adapter installation metadata changes, packaging metadata tests must directly assert that the root project depends unconditionally on the exact-versionnemo-fabric-runtimedistribution.
Packaging metadata tests must verify that each root harness extra delegates to the matching version of the leaf adapter'sharnessextra.
Packaging metadata tests must verify that bare leaf dependencies remain adapter-owned and that the rootadapter-testsdependency group installs each leaf through itsharnessextra.
Packaging metadata tests must verify that every leaf providesfull; only adapters importing NeMo Relay Python APIs providerelay, while adapters using an external Relay executable havefullequal toharness.
Files:
tests/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_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/adapters/test_adapter_package_metadata.pytests/adapters/test_hermes_adapter.py
adapters/*/src/**/*.py
📄 CodeRabbit inference engine (.agents/skills/contribute-adapter/SKILL.md)
adapters/*/src/**/*.py: Implement adapters using the existing Fabricpythonorprocessrunner and normalized request/result contracts; do not add a runner or one-off abstraction for a single adapter.
Treat normalizedconfig, Fabric-resolved plans, andruntime_contextas authoritative; reserveharness.settingsfor adapter-wide behavior and apply precedence in the order: normalized config, plans/context, harness settings, descriptor/default values.
Reject conflicting duplicate declarations and unsupported behavior with actionable errors naming the field and supported alternatives; never silently drop configuration.
Validate dependency versions, hooks, and credentials before harness invocation, and never expose credential values in outputs, errors, events, logs, or fixtures.
Forward only required system, selected credential, telemetry, and documented harness-specific environment variables; never forward or log unrelated environment values.
Maintain one local adapter host per Fabric runtime across orderedstart→invoke*→stopoperations. Emit one JSON lifecycle response per request on stdout and diagnostics on stderr.
Return harness-level invocation failures as successful lifecycle responses containingresponse: null,failed: true, and structurederrorfields (code,message,retryable, and optionalmetadata).
Do not emit NeMo Relay stream records on adapter stdout; return exactly one terminal lifecycle response while streaming occurs through the SDK-owned out-of-band endpoint.
Scope workspace, generated configuration, state, sessions, and artifacts to the resolved runtime context, and isolate stateful adapter instances by Fabric runtime ID.
Usestartto initialize adapter-owned harness state, retain it for continuation across repeatedinvokecalls on the same runtime, and release it instop.
Files:
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
🧠 Learnings (1)
📚 Learning: 2026-07-09T22:28:51.689Z
Learnt from: AjayThorve
Repo: NVIDIA/NeMo-Fabric PR: 43
File: adapters/claude-sdk/src/nemo_fabric_adapters/claude_sdk/adapter.py:164-168
Timestamp: 2026-07-09T22:28:51.689Z
Learning: In the NeMo-Fabric adapters, treat path values used in Fabric adapter configuration (including logic like `_resolve_path` in adapter.py) as config-root-relative. Do not apply `Path.expanduser()` (or otherwise apply `~`/home or shell-style expansion), because it will make the resolved paths normalize inconsistently across adapters. Also, do not rely on or add any resolution behavior that uses `harness.settings.cwd` as an override point for these adapter paths—`harness.settings.cwd` is explicitly unsupported in this adapter context.
Applied to files:
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
🪛 Ruff (0.16.1)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
[warning] 160-162: Avoid specifying long messages outside the exception class
(TRY003)
🔇 Additional comments (3)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py (1)
20-20: LGTM!Also applies to: 147-209, 290-293, 367-372
tests/adapters/test_hermes_adapter.py (2)
62-121: LGTM!Also applies to: 124-180
62-180: 📐 Maintainability & Code QualityRun the required Python validation before merge.
This PR changes a Python adapter and its tests. Run the focused Hermes tests first, then run
just test-python. The PR states thatjust test-pythonwas not run because required tools were unavailable.As per coding guidelines, “If Python code or a Python-facing adapter changes, run
just test-python.”Source: Coding guidelines
Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py (2)
147-211: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd a literal-tilde path regression test.
normalize_relay_output_dirsalready roots relative paths atbase_dirand does not usePath.expanduser()orharness.settings.cwd. Existing tests cover ordinary relative paths; add coverage for literal~.🤖 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/hermes/src/nemo_fabric_adapters/hermes/adapter.py` around lines 147 - 211, Add a regression test for normalize_relay_output_dirs using a literal "~" output path, verifying it remains rooted under base_dir rather than being expanded via Path.expanduser() or harness.settings.cwd. Keep the existing ordinary-relative-path tests and assert the expected normalized path.Sources: Path instructions, Learnings
442-460: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winUse a lifecycle API supported by Hermes 0.19.0.
The lock resolves
hermes-agentto 0.19.0, which does not providehermes_cli.lifecycle. A Relay-enabled invoke therefore raisesModuleNotFoundError. Use a compatible finalization hook or raise the minimum Hermes version and update the lock. Run finalization infinallyand preserve the original turn exception if cleanup fails.🤖 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/hermes/src/nemo_fabric_adapters/hermes/adapter.py` around lines 442 - 460, Update invoke_turn’s Relay finalization to use a lifecycle API available in Hermes 0.19.0, or raise the minimum Hermes dependency and regenerate the lock accordingly. Move finalization into a finally block so it runs for both successful and failed turns, while ensuring any finalization error does not replace the original turn exception.
🤖 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 `@adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py`:
- Around line 147-211: Add a regression test for normalize_relay_output_dirs
using a literal "~" output path, verifying it remains rooted under base_dir
rather than being expanded via Path.expanduser() or harness.settings.cwd. Keep
the existing ordinary-relative-path tests and assert the expected normalized
path.
- Around line 442-460: Update invoke_turn’s Relay finalization to use a
lifecycle API available in Hermes 0.19.0, or raise the minimum Hermes dependency
and regenerate the lock accordingly. Move finalization into a finally block so
it runs for both successful and failed turns, while ensuring any finalization
error does not replace the original turn exception.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 4ac34667-4d43-4307-aa0e-55e5de3d8389
📒 Files selected for processing (1)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
📜 Review details
⏰ Context from checks skipped due to timeout. (18)
- GitHub Check: Preview docs
- GitHub Check: Test (Python 3.11, linux-arm64)
- GitHub Check: Test (Python 3.12, linux-arm64)
- GitHub Check: Test (Python 3.13, windows-amd64)
- GitHub Check: Test (Python 3.14, linux-amd64)
- GitHub Check: Test (Python 3.12, windows-amd64)
- GitHub Check: Test (Python 3.11, windows-amd64)
- GitHub Check: Test (Python 3.14, 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.11, macos-arm64)
- GitHub Check: Test (Python 3.13, linux-arm64)
- GitHub Check: Test (Python 3.13, macos-arm64)
- GitHub Check: Test (Python 3.13, linux-amd64)
- GitHub Check: Test (Python 3.11, linux-amd64)
- GitHub Check: Test (Python 3.14, linux-arm64)
- GitHub Check: Pre-commit
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{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/hermes/src/nemo_fabric_adapters/hermes/adapter.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 spellNVIDIAin all caps; do not useNvidia,nvidia,nVidia,nVIDIA, orNV.
Usean NVIDIAbefore a noun, because the name begins with an “en” sound.
Do not add a registered trademark symbol afterNVIDIAwhen 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 withNVIDIAon 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/hermes/src/nemo_fabric_adapters/hermes/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_casefor functions and variables; usePascalCasefor Rust types and Python classes.
Files:
adapters/hermes/src/nemo_fabric_adapters/hermes/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/hermes/src/nemo_fabric_adapters/hermes/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 injust test-rustpass and review generated schema diffs.
For schema or public contract changes, run both language suites and review changes underschemas/and generated API references.
Files:
adapters/hermes/src/nemo_fabric_adapters/hermes/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, thenjust test-python; rebuild withjust build-pythonwhen native code or packaging changes.Public contract changes must keep native Python binding declarations synchronized with their Rust implementations.
Files:
adapters/hermes/src/nemo_fabric_adapters/hermes/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 inpython/pyproject.toml.
Files:
adapters/hermes/src/nemo_fabric_adapters/hermes/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/hermes/src/nemo_fabric_adapters/hermes/adapter.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/hermes/src/nemo_fabric_adapters/hermes/adapter.py
adapters/*/src/**/*.py
📄 CodeRabbit inference engine (.agents/skills/contribute-adapter/SKILL.md)
adapters/*/src/**/*.py: Implement adapters using the existing Fabricpythonorprocessrunner and normalized request/result contracts; do not add a runner or one-off abstraction for a single adapter.
Treat normalizedconfig, Fabric-resolved plans, andruntime_contextas authoritative; reserveharness.settingsfor adapter-wide behavior and apply precedence in the order: normalized config, plans/context, harness settings, descriptor/default values.
Reject conflicting duplicate declarations and unsupported behavior with actionable errors naming the field and supported alternatives; never silently drop configuration.
Validate dependency versions, hooks, and credentials before harness invocation, and never expose credential values in outputs, errors, events, logs, or fixtures.
Forward only required system, selected credential, telemetry, and documented harness-specific environment variables; never forward or log unrelated environment values.
Maintain one local adapter host per Fabric runtime across orderedstart→invoke*→stopoperations. Emit one JSON lifecycle response per request on stdout and diagnostics on stderr.
Return harness-level invocation failures as successful lifecycle responses containingresponse: null,failed: true, and structurederrorfields (code,message,retryable, and optionalmetadata).
Do not emit NeMo Relay stream records on adapter stdout; return exactly one terminal lifecycle response while streaming occurs through the SDK-owned out-of-band endpoint.
Scope workspace, generated configuration, state, sessions, and artifacts to the resolved runtime context, and isolate stateful adapter instances by Fabric runtime ID.
Usestartto initialize adapter-owned harness state, retain it for continuation across repeatedinvokecalls on the same runtime, and release it instop.
Files:
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.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/hermes/src/nemo_fabric_adapters/hermes/adapter.py
🧠 Learnings (1)
📚 Learning: 2026-07-09T22:28:51.689Z
Learnt from: AjayThorve
Repo: NVIDIA/NeMo-Fabric PR: 43
File: adapters/claude-sdk/src/nemo_fabric_adapters/claude_sdk/adapter.py:164-168
Timestamp: 2026-07-09T22:28:51.689Z
Learning: In the NeMo-Fabric adapters, treat path values used in Fabric adapter configuration (including logic like `_resolve_path` in adapter.py) as config-root-relative. Do not apply `Path.expanduser()` (or otherwise apply `~`/home or shell-style expansion), because it will make the resolved paths normalize inconsistently across adapters. Also, do not rely on or add any resolution behavior that uses `harness.settings.cwd` as an override point for these adapter paths—`harness.settings.cwd` is explicitly unsupported in this adapter context.
Applied to files:
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
🔇 Additional comments (4)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py (4)
466-466: The cancellation race remains unresolved.
asyncio.to_thread(invoke_turn)is not tracked. Ifinvoke()is cancelled,stop()can clear and close_agentand_session_dband restore Relay environment state whileinvoke_turn()still runs. Track and await the worker before cleanup.Also applies to: 502-535
450-460: 🗄️ Data Integrity & IntegrationVerify the per-invocation finalization boundary.
HermesRuntimereuses one agent, session ID, and conversation history acrossinvoke*, butfinalize_session()is a session-finalization API. The current Hermes lifecycle implementation closes the Relay session and dispatcheson_session_finalize; Hermes documentation describes this hook as session teardown. (raw.githubusercontent.com)Confirm that the pinned Hermes versions support reopening the same session ID for each invocation. Add a two-invocation test for ATIF output and plugin lifecycle callbacks.
324-343: 📐 Maintainability & Code QualityRun the required Python suite before merge.
The adapter changed, but the PR validation did not run
just test-python. Run the focused Hermes tests first, thenjust test-python, and format the changed file before the final pass.As per coding guidelines, if Python code or a Python-facing adapter changes, run
just test-python.Source: Coding guidelines
324-343: 🗄️ Data Integrity & IntegrationDo not add a process-wide Relay lease for this path.
The lifecycle host owns one runtime and rejects a second
startwhile it is active. Supported Hermes runtimes therefore do not overlap in one process.> Likely an incorrect or invalid review comment.
Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py`:
- Around line 514-525: Add a completion callback to the invoke_task created in
the invocation flow so it clears _active_invoke_task when that task finishes,
but only if the field still references the same task. Keep the existing finally
cleanup for already-completed tasks and preserve the current cancellation
behavior while ensuring later invoke() calls can proceed after an abandoned
worker turn completes.
In `@python/src/nemo_fabric/streaming.py`:
- Around line 527-541: Update the turn-scope matching logic around
_legacy_hermes_turn_id and _turn_scope_uuids so a scope-start record matched by
metadata.turn_id records its uuid in _turn_scope_uuids before returning.
Preserve existing matching behavior, and add regression coverage ensuring
descendants without metadata.turn_id remain included.
- Around line 562-570: Update _matches_turn_root() and the begin_stream()
listener lifecycle so late hermes.turn.start marks from a prior ATOF invocation
cannot establish a new root; require invocation/request correlation (or
guarantee the connection is drained before re-enabling the shared listener) in
addition to the existing Fabric and turn_id checks. Add a sequential regression
test covering a late mark emitted after one stream ends and before the next
begins, verifying stale records are not admitted.
🪄 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: 7e098f3e-9787-4e6a-af36-a768a4768a0a
📒 Files selected for processing (6)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.pypython/src/nemo_fabric/streaming.pytests/adapters/test_hermes_adapter.pytests/adapters/test_hermes_streaming.pytests/e2e/test_hermes_e2e.pytests/python/test_streaming.py
📜 Review details
⏰ Context from checks skipped due to timeout. (18)
- GitHub Check: Preview docs
- GitHub Check: Test (Python 3.12, windows-amd64)
- GitHub Check: Test (Python 3.14, windows-amd64)
- GitHub Check: Test (Python 3.13, windows-amd64)
- GitHub Check: Test (Python 3.11, windows-amd64)
- GitHub Check: Test (Python 3.13, macos-arm64)
- GitHub Check: Test (Python 3.13, linux-amd64)
- GitHub Check: Test (Python 3.14, macos-arm64)
- GitHub Check: Test (Python 3.11, linux-arm64)
- GitHub Check: Test (Python 3.13, linux-arm64)
- GitHub Check: Test (Python 3.11, macos-arm64)
- GitHub Check: Test (Python 3.14, linux-arm64)
- GitHub Check: Test (Python 3.11, linux-amd64)
- GitHub Check: Test (Python 3.12, linux-arm64)
- GitHub Check: Test (Python 3.12, macos-arm64)
- GitHub Check: Test (Python 3.12, linux-amd64)
- GitHub Check: Test (Python 3.14, linux-amd64)
- GitHub Check: Pre-commit
🧰 Additional context used
📓 Path-based instructions (18)
**/*.{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/e2e/test_hermes_e2e.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pypython/src/nemo_fabric/streaming.pytests/adapters/test_hermes_streaming.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.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 spellNVIDIAin all caps; do not useNvidia,nvidia,nVidia,nVIDIA, orNV.
Usean NVIDIAbefore a noun, because the name begins with an “en” sound.
Do not add a registered trademark symbol afterNVIDIAwhen 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 withNVIDIAon 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/e2e/test_hermes_e2e.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pypython/src/nemo_fabric/streaming.pytests/adapters/test_hermes_streaming.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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_casefor functions and variables; usePascalCasefor Rust types and Python classes.
Files:
tests/e2e/test_hermes_e2e.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pypython/src/nemo_fabric/streaming.pytests/adapters/test_hermes_streaming.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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:
tests/e2e/test_hermes_e2e.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pypython/src/nemo_fabric/streaming.pytests/adapters/test_hermes_streaming.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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 injust test-rustpass and review generated schema diffs.
For schema or public contract changes, run both language suites and review changes underschemas/and generated API references.
Files:
tests/e2e/test_hermes_e2e.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pypython/src/nemo_fabric/streaming.pytests/adapters/test_hermes_streaming.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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, thenjust test-python; rebuild withjust build-pythonwhen native code or packaging changes.Public contract changes must keep native Python binding declarations synchronized with their Rust implementations.
Files:
tests/e2e/test_hermes_e2e.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pypython/src/nemo_fabric/streaming.pytests/adapters/test_hermes_streaming.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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 inpython/pyproject.toml.
Files:
tests/e2e/test_hermes_e2e.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pypython/src/nemo_fabric/streaming.pytests/adapters/test_hermes_streaming.pyadapters/hermes/src/nemo_fabric_adapters/hermes/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:
tests/e2e/test_hermes_e2e.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pypython/src/nemo_fabric/streaming.pytests/adapters/test_hermes_streaming.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.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:
tests/e2e/test_hermes_e2e.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pypython/src/nemo_fabric/streaming.pytests/adapters/test_hermes_streaming.pyadapters/hermes/src/nemo_fabric_adapters/hermes/adapter.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/e2e/test_hermes_e2e.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pytests/adapters/test_hermes_streaming.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.asyncioto tests; async tests are automatically detected by the async runner.
Do not add-> Nonereturn type annotations to test functions.
When mocking a class, useunittest.mock.MagicMockorAsyncMock, using thespecargument when necessary, rather than defining a new class.
Prefix mocked class names withmock, notfake.
Prefer pytest fixtures over helper methods.
If a fixture is needed in multiple test files, define it once inconftest.pyrather than repeating it.
Define fixtures using@pytest.fixture(name="<fixture_name>"[, scope="<scope>"])and a<fixture_name>_fixturefunction; specifyscopeonly when it is notfunction.
Preferpytest.mark.parametrizeover separate tests for different input types.
Use@pytest.mark.usefixtureswhen 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 usingresults["data"]instead ofresults.get("data").
When adapter installation metadata changes, packaging metadata tests must directly assert that the root project depends unconditionally on the exact-versionnemo-fabric-runtimedistribution.
Packaging metadata tests must verify that each root harness extra delegates to the matching version of the leaf adapter'sharnessextra.
Packaging metadata tests must verify that bare leaf dependencies remain adapter-owned and that the rootadapter-testsdependency group installs each leaf through itsharnessextra.
Packaging metadata tests must verify that every leaf providesfull; only adapters importing NeMo Relay Python APIs providerelay, while adapters using an external Relay executable havefullequal toharness.
Files:
tests/e2e/test_hermes_e2e.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pytests/adapters/test_hermes_streaming.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_hermes_e2e.pytests/python/test_streaming.pytests/adapters/test_hermes_adapter.pytests/adapters/test_hermes_streaming.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 undertests/adapters, then runjust test-python.
Files:
tests/adapters/test_hermes_adapter.pytests/adapters/test_hermes_streaming.py
python/src/nemo_fabric/**/*.py
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/SKILL.md)
For Python API reference changes, update source docstrings under
python/src/nemo_fabric/instead of generated API reference files.
Files:
python/src/nemo_fabric/streaming.py
python/src/nemo_fabric/**/*.{py,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure native extension naming and placement remain compatible with downstream consumers, including the editable maturin build producing
nemo_fabric._native.
Files:
python/src/nemo_fabric/streaming.py
python/src/nemo_fabric/**/*
⚙️ CodeRabbit configuration file
python/src/nemo_fabric/**/*: Review Python SDK changes for typed API consistency, import-time dependency neutrality, async/session behavior, and parity with the native extension.
Stubs and runtime implementations should stay aligned.
Files:
python/src/nemo_fabric/streaming.py
adapters/*/src/**/*.py
📄 CodeRabbit inference engine (.agents/skills/contribute-adapter/SKILL.md)
adapters/*/src/**/*.py: Implement adapters using the existing Fabricpythonorprocessrunner and normalized request/result contracts; do not add a runner or one-off abstraction for a single adapter.
Treat normalizedconfig, Fabric-resolved plans, andruntime_contextas authoritative; reserveharness.settingsfor adapter-wide behavior and apply precedence in the order: normalized config, plans/context, harness settings, descriptor/default values.
Reject conflicting duplicate declarations and unsupported behavior with actionable errors naming the field and supported alternatives; never silently drop configuration.
Validate dependency versions, hooks, and credentials before harness invocation, and never expose credential values in outputs, errors, events, logs, or fixtures.
Forward only required system, selected credential, telemetry, and documented harness-specific environment variables; never forward or log unrelated environment values.
Maintain one local adapter host per Fabric runtime across orderedstart→invoke*→stopoperations. Emit one JSON lifecycle response per request on stdout and diagnostics on stderr.
Return harness-level invocation failures as successful lifecycle responses containingresponse: null,failed: true, and structurederrorfields (code,message,retryable, and optionalmetadata).
Do not emit NeMo Relay stream records on adapter stdout; return exactly one terminal lifecycle response while streaming occurs through the SDK-owned out-of-band endpoint.
Scope workspace, generated configuration, state, sessions, and artifacts to the resolved runtime context, and isolate stateful adapter instances by Fabric runtime ID.
Usestartto initialize adapter-owned harness state, retain it for continuation across repeatedinvokecalls on the same runtime, and release it instop.
Files:
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.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/hermes/src/nemo_fabric_adapters/hermes/adapter.py
🧠 Learnings (2)
📚 Learning: 2026-06-28T04:03:32.877Z
Learnt from: AjayThorve
Repo: NVIDIA/NeMo-Fabric PR: 26
File: python/tests/smoke_typed_config.py:163-177
Timestamp: 2026-06-28T04:03:32.877Z
Learning: In NVIDIA NeMo Fabric Python SDK serialization of `RuntimeCapabilities` (to satisfy the “parity contract” with Rust core and the CLI), do not emit metadata keys when the corresponding metadata is absent. Instead, omit those fields entirely so the produced JSON matches the Rust/CLI output (e.g., avoid `null`, empty objects, or placeholder metadata). During review, verify the serializer/builders follow this omission rule and that Python outputs/parity tests reflect the same shape.
Applied to files:
python/src/nemo_fabric/streaming.py
📚 Learning: 2026-07-09T22:28:51.689Z
Learnt from: AjayThorve
Repo: NVIDIA/NeMo-Fabric PR: 43
File: adapters/claude-sdk/src/nemo_fabric_adapters/claude_sdk/adapter.py:164-168
Timestamp: 2026-07-09T22:28:51.689Z
Learning: In the NeMo-Fabric adapters, treat path values used in Fabric adapter configuration (including logic like `_resolve_path` in adapter.py) as config-root-relative. Do not apply `Path.expanduser()` (or otherwise apply `~`/home or shell-style expansion), because it will make the resolved paths normalize inconsistently across adapters. Also, do not rely on or add any resolution behavior that uses `harness.settings.cwd` as an override point for these adapter paths—`harness.settings.cwd` is explicitly unsupported in this adapter context.
Applied to files:
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
🪛 Ruff (0.16.1)
tests/e2e/test_hermes_e2e.py
[warning] 121-121: Async functions should not call blocking HTTP methods
(ASYNC210)
tests/adapters/test_hermes_adapter.py
[warning] 227-227: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 906-906: Missing return type annotation for private function run_turn
(ANN202)
[warning] 906-906: Missing type annotation for **_kwargs
(ANN003)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py
[warning] 567-567: Do not catch blind exception: BaseException
(BLE001)
🔇 Additional comments (7)
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py (2)
40-42: LGTM!Also applies to: 54-66, 328-332, 363-382, 561-604
69-86: 🎯 Functional CorrectnessNo change needed: the sink lookup matches the staged v2 and v3 configuration paths.
tests/adapters/test_hermes_adapter.py (1)
8-14: LGTM!Also applies to: 185-199, 222-236, 255-257, 900-951
python/src/nemo_fabric/streaming.py (1)
258-258: LGTM!Also applies to: 312-312, 327-327, 580-583
tests/adapters/test_hermes_streaming.py (1)
85-89: LGTM!tests/python/test_streaming.py (1)
934-975: LGTM!tests/e2e/test_hermes_e2e.py (1)
10-14: LGTM!Also applies to: 111-123, 187-195, 331-366, 396-402
Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
Overview
Update the Hermes adapter to use Hermes Agent's bundled
observability/nemo_relayintegration. Relay remains a loose, upstream-compatibleHermes adapter dependency:
nemo-relay>=0.6.0,<0.8.The published Hermes Agent 0.19.0 package supports Relay 0.6.x and exposes the
upstream
on_session_finalizeplugin hook. Newer upstream Hermes releases canresolve the 0.7.x line; the range allows each Hermes release to resolve its
compatible Relay version.
Details
file consumed by Hermes' upstream plugin. No ATIF TOML-to-environment mapping.
TOML-configured ATIF is complete before Fabric returns. Newer Hermes uses its
public lifecycle API; published 0.19 uses the equivalent upstream plugin hook.
invocation worker is still finalizing.
Fabric streaming.
from affecting a failed initialization.
Claude/Codex gateways remain on Relay 0.6's public observability-v2 contract.
Validation
ruff formatandruff checkon changed Python filesRelay 0.7.2 injected to exercise the v3 path.
uv lock --check, adapter lock check, and Hermes wheel metadata verificationNot run:
just test-python(justunavailable); Rust license and attributionchecks (
cargo/cargo-aboutunavailable).Where should the reviewer start?
Start with
adapters/hermes/src/nemo_fabric_adapters/hermes/adapter.py, thenreview
tests/adapters/test_hermes_adapter.pyandtests/e2e/test_hermes_e2e.py.Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)
Summary by CodeRabbit
New Features
Bug Fixes