feat: add local backend for built-in nemo guardrails#197
Conversation
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
|
Looking for one thing? Review this PR in Change Stack to search files, summaries, diffs, and code without losing your place. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Enterprise Run ID: 📒 Files selected for processing (2)
📜 Recent review details🧰 Additional context used📓 Path-based instructions (19){docs/**,README.md,CONTRIBUTING.md}📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Files:
{docs/**,README.md,CONTRIBUTING.md,**/*.md}📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Files:
{docs/**,README.md}📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Files:
{docs/**,examples/**,README.md}📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Files:
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Files:
**/*.{md,mdx,py,sh,yaml,yml,toml,json}📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Files:
**/*.mdx📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Files:
**/*.{html,md,mdx}📄 CodeRabbit inference engine (CONTRIBUTING.md)
Files:
docs/**/*.{md,mdx}📄 CodeRabbit inference engine (CONTRIBUTING.md)
Files:
docs/**📄 CodeRabbit inference engine (CONTRIBUTING.md)
Files:
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}⚙️ CodeRabbit configuration file
Files:
**⚙️ CodeRabbit configuration file
Files:
{pyproject.toml,**/*.py}📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Files:
{crates/core,crates/adaptive}/**/*📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Files:
**/*.{py,txt,toml,cfg,yaml,yml}📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Files:
crates/{core,adaptive}/**📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Files:
**/*.py📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Files:
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{rs,py,go,js,ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🪛 Ruff (0.15.15)crates/core/src/plugins/nemo_guardrails/local_worker.py[warning] 214-214: Too many branches (14 > 12) (PLR0912) [warning] 274-274: Do not catch blind exception: (BLE001) 🔇 Additional comments (5)
WalkthroughAdds a production-ready local NeMo Guardrails backend using a Python subprocess worker, updates schema/validation and plugin registration, implements Rust bridge and worker protocol with streaming support, adds extensive unit/integration tests, and updates documentation. ChangesLocal Backend Configuration & Registration
Python Plugin Registration
Local Backend Runtime Implementation
Testing & Validation
Documentation & Configuration Guides
🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Signed-off-by: Alex Fournier <afournier@nvidia.com>
|
/ok to test 98d4915 |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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 `@crates/python/src/lib.rs`:
- Around line 112-121: The current retry unconditionally swallows any py.import
error and prepends source_python_dir; change load_guardrails_local_register_fn
to only attempt the fallback when the original PyErr is specifically a
ModuleNotFoundError for "nemo_relay" or "nemo_relay._guardrails_local": capture
the Err(err) from py.import, inspect its Python exception type (e.g. compare
against pyo3::exceptions::PyModuleNotFoundError) and/or the exception message to
ensure it indicates the module is missing, and only then check
source_python_dir, call prepend_python_path_if_missing(py, &source_python_dir)
and retry the import; for any other error type, immediately return Err(err)
unchanged (preserving the original error).
In `@crates/python/src/py_plugin.rs`:
- Around line 177-181: The call to register_fn.call1((plugin_config_py,
py_ctx.clone_ref(py))) can raise after partial registrations were made, but the
current code only drains registrations on the success path; to fix, call
register_fn.call1 and capture its Result, and if it Errs then immediately bind
the PyPluginContext (py_ctx.bind(py).borrow()) and call drain_registrations() to
rollback any partial registrations before returning the Err; keep the
successful-path behavior unchanged. Use the existing symbols register_fn.call1,
py_ctx, PyPluginContext (py_ctx.bind(py).borrow()), and drain_registrations() to
locate and implement the error-path cleanup.
In `@crates/python/tests/coverage/coverage_tests.rs`:
- Around line 344-357: The test currently only asserts check_calls length, which
misses verifying the actual guardrail kinds; update the assertions to explicitly
assert the captured guardrail sequence from result_json["check_calls"] matches
the expected rail types in order (input, output, tool_input, tool_output) and
also validate each call's input payload where relevant (use the recorded
(messages, rail_types) entries from the fake backend), replacing the len() check
with explicit equality checks against the expected sequence so order and types
are enforced (refer to check_calls, seen_request_messages, seen_tool_args, and
llm_result in the diff to locate the assertions to update).
- Around line 232-236: The tests mutate Python's sys.modules for the nemo_relay
namespace without isolating changes; add a small helper (e.g.,
snapshot_and_swap_nemo_relay or with_nemo_relay_modules) that, given a Python
GIL/python interpreter handle, snapshots all sys.modules keys starting with
"nemo_relay", clears or removes those keys, yields to a closure where you
perform the modules.set_item("nemo_relay._native", native_module.clone()) swap,
and finally restores the original snapshot even on panic; replace the direct
modules.set_item calls in
test_guardrails_local_helper_registers_and_enforces_llm_and_tool_checks,
test_guardrails_local_helper_enforces_streamed_output_rails, and
test_local_guardrails_provider_initializes_and_enforces_managed_core_calls with
this helper so each test always restores the full nemo_relay.* entries.
In `@python/nemo_relay/_guardrails_local.py`:
- Around line 455-486: The monitor task is created eagerly which leaks when the
returned async generator (guarded_provider_stream) is never iterated; move
creation of text_queue, blocked and the asyncio.create_task(...) that starts
_monitor_streaming_output_rails into the start of guarded_provider_stream so the
monitor is only created when the generator is actually consumed, keep the
existing finally block logic (await text_queue.put(None); await monitor;
re-check blocked["message"] and call _raise_streaming_output_blocked if needed),
and ensure you still use _extract_stream_text, stream and blocked inside the
generator as before.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 37c4df6f-db71-420c-b283-495a31160158
📒 Files selected for processing (11)
crates/core/src/plugins/nemo_guardrails/component.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/python/src/lib.rscrates/python/src/py_plugin.rscrates/python/tests/coverage/coverage_tests.rsdocs/about-nemo-relay/concepts/plugins.mdxdocs/build-plugins/nemoguardrails.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdxpython/nemo_relay/_guardrails_local.py
💤 Files with no reviewable changes (1)
- docs/build-plugins/nemoguardrails.mdx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (32)
{docs/**,README.md,CONTRIBUTING.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Usejust docsfor docs-site builds andjust docs-linkcheckwhen links changed
Run docs site build withjust docs
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run docs link validation with
just docs-linkcheckwhen links change
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify README and docs entry points still match current package names and paths for large or public-facing changes
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,examples/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify examples still run with documented commands for large or public-facing changes
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
**/*.{md,mdx,py,sh,yaml,yml,toml,json}
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Keep package names, repo references, and build commands current
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxpython/nemo_relay/_guardrails_local.pydocs/nemo-guardrails-plugin/configuration.mdx
**/*.mdx
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.
MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
**/*.{html,md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in HTML and Markdown files using HTML comment syntax
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
docs/**/*.{md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
docs/**
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run
just docsor./scripts/build-docs.sh htmlto regenerate ignored Fern API reference pages before validation for documentation site changes
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}
⚙️ CodeRabbit configuration file
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings.
Flag stale examples, missing SPDX headers where required, and instructions that no longer match CI or pre-commit behavior.
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/python/src/py_plugin.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/python/tests/coverage/coverage_tests.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/python/src/py_plugin.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/python/tests/coverage/coverage_tests.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/python/src/py_plugin.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/python/tests/coverage/coverage_tests.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/component.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/python/src/py_plugin.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/python/tests/coverage/coverage_tests.rs
crates/core/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
If the change touched
crates/coreor shared runtime semantics, also usevalidate-changefor broader validation
crates/core/**/*.rs: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/component.rs
crates/{core,adaptive}/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/component.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/python/src/py_plugin.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/python/tests/coverage/coverage_tests.rspython/nemo_relay/_guardrails_local.py
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/python/src/py_plugin.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/python/tests/coverage/coverage_tests.rspython/nemo_relay/_guardrails_local.py
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/python/src/py_plugin.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/python/tests/coverage/coverage_tests.rs
crates/{core,adaptive}/**/*.rs
⚙️ CodeRabbit configuration file
crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/component.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/python/tests/coverage/coverage_tests.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/python/tests/coverage/coverage_tests.rs
crates/python/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
If the native Rust bridge changed, add the Rust crate tests for
nemo-relay-python
Files:
crates/python/src/py_plugin.rscrates/python/src/lib.rscrates/python/tests/coverage/coverage_tests.rs
crates/{python,ffi,node,wasm}/**/*
⚙️ CodeRabbit configuration file
crates/{python,ffi,node,wasm}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.
Files:
crates/python/src/py_plugin.rscrates/python/src/lib.rscrates/python/tests/coverage/coverage_tests.rs
{crates/python/src/py_api/**/*.rs,python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi}
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Update Python native binding in
crates/python/src/py_api/mod.rswith Python wrapper docstring inpython/nemo_relay/<module>.pyand type stubs inpython/nemo_relay/*.pyimodules
Files:
python/nemo_relay/_guardrails_local.py
python/nemo_relay/**/*.py
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Python identifiers (e.g.,nemo_relay.tools.call)Format changed Python wrapper and test files with
uv run ruff format pythonPython wrapper modules live under
python/nemo_relay/; the native extension is built fromcrates/pythonwithmaturin.
Files:
python/nemo_relay/_guardrails_local.py
{pyproject.toml,**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Python package names in
pyproject.tomland import paths used throughout the codebase
Files:
python/nemo_relay/_guardrails_local.py
**/*.{py,txt,toml,cfg,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Python package names and top-level module imports during coordinated rename operations
Files:
python/nemo_relay/_guardrails_local.py
**/*.py
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*.py: Run Python formatting withuv run ruff format python
Run Python testing withuv run pytest -k "<pattern>"
**/*.py: Use Ruff with rule sets E, F, W, I for Python linting
Use Ruff formatter with line length 120 and double quotes for Python code formatting
Runtyfor Python type checking
Use Python snake_case naming convention for Python identifiers
Include SPDX license header in all Python source files using hash comment syntax
Validate Python code withuv run pre-commit run --all-filesto enforce Ruff linting and formatting, and ty type checking
Files:
python/nemo_relay/_guardrails_local.py
python/nemo_relay/**/*
⚙️ CodeRabbit configuration file
python/nemo_relay/**/*: Review Python wrapper changes for typed API consistency, contextvars-based scope isolation, async behavior, and parity with the native extension.
Stubs and runtime implementations should stay aligned.
Files:
python/nemo_relay/_guardrails_local.py
🪛 LanguageTool
docs/nemo-guardrails-plugin/configuration.mdx
[style] ~294-~294: To form a complete sentence, be sure to include a subject.
Context: ...g_yamlis required. -colang_contentcan only be used withconfig_yaml. - rem...
(MISSING_IT_THERE)
🪛 Ruff (0.15.15)
python/nemo_relay/_guardrails_local.py
[warning] 59-59: Missing return type annotation for private function _load_nemoguardrails
(ANN202)
[warning] 66-69: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 70-73: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 83-83: Dynamically typed expressions (typing.Any) are disallowed in status
(ANN401)
[warning] 87-87: Dynamically typed expressions (typing.Any) are disallowed in annotated
(ANN401)
[warning] 92-92: Dynamically typed expressions (typing.Any) are disallowed in rails
(ANN401)
[warning] 93-93: Dynamically typed expressions (typing.Any) are disallowed in rail_type
(ANN401)
[warning] 94-94: Dynamically typed expressions (typing.Any) are disallowed in rail_status
(ANN401)
[warning] 122-126: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 156-160: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 163-167: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 171-171: Dynamically typed expressions (typing.Any) are disallowed in result
(ANN401)
[warning] 174-180: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 184-184: Dynamically typed expressions (typing.Any) are disallowed in rails
(ANN401)
[warning] 185-185: Dynamically typed expressions (typing.Any) are disallowed in rail_type
(ANN401)
[warning] 186-186: Dynamically typed expressions (typing.Any) are disallowed in rail_status
(ANN401)
[warning] 202-202: Dynamically typed expressions (typing.Any) are disallowed in rails
(ANN401)
[warning] 206-206: Dynamically typed expressions (typing.Any) are disallowed in rails
(ANN401)
[warning] 206-206: Dynamically typed expressions (typing.Any) are disallowed in _output_streaming_config
(ANN401)
[warning] 210-210: Dynamically typed expressions (typing.Any) are disallowed in rails
(ANN401)
[warning] 215-215: Too many return statements (10 > 6)
(PLR0911)
[warning] 215-215: Too many branches (13 > 12)
(PLR0912)
[warning] 271-271: Missing return type annotation for private function _queue_string_stream
(ANN202)
[warning] 271-271: Remove quotes from type annotation
Remove quotes
(UP037)
[warning] 281-281: Dynamically typed expressions (typing.Any) are disallowed in rails
(ANN401)
[warning] 283-283: Remove quotes from type annotation
Remove quotes
(UP037)
[warning] 300-304: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 307-307: Dynamically typed expressions (typing.Any) are disallowed in rails_config_cls
(ANN401)
[warning] 307-307: Dynamically typed expressions (typing.Any) are disallowed in _build_guardrails_config
(ANN401)
[warning] 319-319: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 324-324: Dynamically typed expressions (typing.Any) are disallowed in rails
(ANN401)
[warning] 325-325: Dynamically typed expressions (typing.Any) are disallowed in rail_type
(ANN401)
[warning] 326-326: Dynamically typed expressions (typing.Any) are disallowed in rail_status
(ANN401)
[warning] 347-347: Dynamically typed expressions (typing.Any) are disallowed in rails
(ANN401)
[warning] 348-348: Dynamically typed expressions (typing.Any) are disallowed in rail_type
(ANN401)
[warning] 349-349: Dynamically typed expressions (typing.Any) are disallowed in rail_status
(ANN401)
[warning] 376-376: Missing return type annotation for private function _make_llm_intercept
(ANN202)
[warning] 378-378: Dynamically typed expressions (typing.Any) are disallowed in rails
(ANN401)
[warning] 379-379: Dynamically typed expressions (typing.Any) are disallowed in rail_type
(ANN401)
[warning] 380-380: Dynamically typed expressions (typing.Any) are disallowed in rail_status
(ANN401)
[warning] 385-385: Missing return type annotation for private function intercept
(ANN202)
[warning] 415-415: Missing return type annotation for private function _make_llm_stream_intercept
(ANN202)
[warning] 417-417: Dynamically typed expressions (typing.Any) are disallowed in rails
(ANN401)
[warning] 418-418: Dynamically typed expressions (typing.Any) are disallowed in rail_type
(ANN401)
[warning] 419-419: Dynamically typed expressions (typing.Any) are disallowed in rail_status
(ANN401)
[warning] 425-425: Missing return type annotation for private function stream_intercept
(ANN202)
[warning] 443-446: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 450-453: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 466-466: Missing return type annotation for private function guarded_provider_stream
(ANN202)
[warning] 491-491: Missing return type annotation for private function _make_tool_intercept
(ANN202)
[warning] 493-493: Dynamically typed expressions (typing.Any) are disallowed in rails
(ANN401)
[warning] 494-494: Dynamically typed expressions (typing.Any) are disallowed in rail_type
(ANN401)
[warning] 495-495: Dynamically typed expressions (typing.Any) are disallowed in rail_status
(ANN401)
[warning] 499-499: Missing return type annotation for private function tool_intercept
(ANN202)
[warning] 527-527: Dynamically typed expressions (typing.Any) are disallowed in result
(ANN401)
[warning] 533-538: Avoid specifying long messages outside the exception class
(TRY003)
🔇 Additional comments (12)
crates/core/src/plugins/nemo_guardrails/local.rs (2)
17-37: LGTM!
39-51: Lock-free invocation is the right call. Cloning the provider handle and dropping theMutexGuardbefore invoking avoids re-entrancy deadlock if the provider touches the registry, and keeps the lock off the async registration path.crates/core/src/plugins/nemo_guardrails/component.rs (2)
20-28: LGTM!Also applies to: 454-454
960-970: Local-moderequest_defaultsrejection is consistent. Early-return correctly short-circuits the remote-only field checks. Note the diagnostic honorspolicy.unsupported_value, so anIgnorepolicy will pass validation and forwardrequest_defaultsto the provider — that matches policy semantics, just confirm the Python backend tolerates/ignores the field rather than erroring.crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs (1)
43-49: Coverage and isolation look solid.reset_runtimeclearing the provider at each test entry (undertest_mutex) keeps the new dispatch test from leaking registration state into siblings, and the assertions inside the provider closure verify both invocation and config propagation.Also applies to: 793-807, 995-995, 1027-1054
docs/about-nemo-relay/concepts/plugins.mdx (1)
174-177: LGTM!docs/nemo-guardrails-plugin/about.mdx (3)
23-55: LGTM!
59-116: LGTM!
121-121: LGTM!docs/nemo-guardrails-plugin/configuration.mdx (3)
37-59: LGTM!
61-197: LGTM!
211-345: LGTM!
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
|
/ok to test 67fd1b9 |
willkill07
left a comment
There was a problem hiding this comment.
Overall the design looks good. Let's propagate the logic as embedded rust/python code rather than needing nemo-relay installed.
Also, we need to fix CI (which is failing)
Signed-off-by: Alex Fournier <afournier@nvidia.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
crates/python/src/lib.rs (1)
155-166:⚠️ Potential issue | 🟠 Major | ⚡ Quick winOnly fall back to
../../pythonon a true missing-module error.This still treats any
py.import("nemo_relay")failure as recoverable, so an installed-but-broken package can be silently shadowed by the source tree. Preserve the originalPyErr, retry only forModuleNotFoundErroronnemo_relay, and return that original error unchanged when the source tree is absent.🤖 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 `@crates/python/src/lib.rs` around lines 155 - 166, In ensure_nemo_relay_package_importable, preserve and inspect the original PyErr from py.import("nemo_relay") instead of treating any failure as recoverable: call py.import and if it returns Err, capture that error, check whether it is a ModuleNotFoundError specifically for the "nemo_relay" name; only then proceed to check embedded_guardrails_source_python_dir and call prepend_python_path_if_missing and retry import via py.import; if the source tree is absent return the original PyErr unchanged, and if the original error was not ModuleNotFoundError for "nemo_relay" return it immediately (do not shadow a broken installed package).
🤖 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.
Duplicate comments:
In `@crates/python/src/lib.rs`:
- Around line 155-166: In ensure_nemo_relay_package_importable, preserve and
inspect the original PyErr from py.import("nemo_relay") instead of treating any
failure as recoverable: call py.import and if it returns Err, capture that
error, check whether it is a ModuleNotFoundError specifically for the
"nemo_relay" name; only then proceed to check
embedded_guardrails_source_python_dir and call prepend_python_path_if_missing
and retry import via py.import; if the source tree is absent return the original
PyErr unchanged, and if the original error was not ModuleNotFoundError for
"nemo_relay" return it immediately (do not shadow a broken installed package).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 505b1e7e-510f-4922-89e9-b887e63991ad
📒 Files selected for processing (4)
crates/python/embedded_python/_guardrails_local.pycrates/python/src/lib.rscrates/python/tests/coverage/coverage_tests.rsdocs/nemo-guardrails-plugin/configuration.mdx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (25)
{pyproject.toml,**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Python package names in
pyproject.tomland import paths used throughout the codebase
Files:
crates/python/embedded_python/_guardrails_local.py
**/*.{py,txt,toml,cfg,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Python package names and top-level module imports during coordinated rename operations
Files:
crates/python/embedded_python/_guardrails_local.py
**/*.py
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*.py: Run Python formatting withuv run ruff format python
Run Python testing withuv run pytest -k "<pattern>"
**/*.py: Use Ruff with rule sets E, F, W, I for Python linting
Use Ruff formatter with line length 120 and double quotes for Python code formatting
Runtyfor Python type checking
Use Python snake_case naming convention for Python identifiers
Include SPDX license header in all Python source files using hash comment syntax
Validate Python code withuv run pre-commit run --all-filesto enforce Ruff linting and formatting, and ty type checking
Files:
crates/python/embedded_python/_guardrails_local.py
**/*.{md,mdx,py,sh,yaml,yml,toml,json}
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Keep package names, repo references, and build commands current
Files:
crates/python/embedded_python/_guardrails_local.pydocs/nemo-guardrails-plugin/configuration.mdx
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/python/embedded_python/_guardrails_local.pycrates/python/tests/coverage/coverage_tests.rscrates/python/src/lib.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/python/embedded_python/_guardrails_local.pycrates/python/tests/coverage/coverage_tests.rscrates/python/src/lib.rs
crates/{python,ffi,node,wasm}/**/*
⚙️ CodeRabbit configuration file
crates/{python,ffi,node,wasm}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.
Files:
crates/python/embedded_python/_guardrails_local.pycrates/python/tests/coverage/coverage_tests.rscrates/python/src/lib.rs
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/python/tests/coverage/coverage_tests.rscrates/python/src/lib.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
crates/python/tests/coverage/coverage_tests.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/python/tests/coverage/coverage_tests.rscrates/python/src/lib.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/python/tests/coverage/coverage_tests.rscrates/python/src/lib.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/python/tests/coverage/coverage_tests.rscrates/python/src/lib.rs
crates/python/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
If the native Rust bridge changed, add the Rust crate tests for
nemo-relay-python
Files:
crates/python/tests/coverage/coverage_tests.rscrates/python/src/lib.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/python/tests/coverage/coverage_tests.rscrates/python/src/lib.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/python/tests/coverage/coverage_tests.rs
{docs/**,README.md,CONTRIBUTING.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Usejust docsfor docs-site builds andjust docs-linkcheckwhen links changed
Run docs site build withjust docs
Files:
docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run docs link validation with
just docs-linkcheckwhen links change
Files:
docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify README and docs entry points still match current package names and paths for large or public-facing changes
Files:
docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,examples/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify examples still run with documented commands for large or public-facing changes
Files:
docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes
Files:
docs/nemo-guardrails-plugin/configuration.mdx
**/*.mdx
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.
MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)
Files:
docs/nemo-guardrails-plugin/configuration.mdx
**/*.{html,md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in HTML and Markdown files using HTML comment syntax
Files:
docs/nemo-guardrails-plugin/configuration.mdx
docs/**/*.{md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed
Files:
docs/nemo-guardrails-plugin/configuration.mdx
docs/**
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run
just docsor./scripts/build-docs.sh htmlto regenerate ignored Fern API reference pages before validation for documentation site changes
Files:
docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}
⚙️ CodeRabbit configuration file
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings.
Flag stale examples, missing SPDX headers where required, and instructions that no longer match CI or pre-commit behavior.
Files:
docs/nemo-guardrails-plugin/configuration.mdx
🪛 Ruff (0.15.15)
crates/python/embedded_python/_guardrails_local.py
[warning] 80-83: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 87-91: Avoid specifying long messages outside the exception class
(TRY003)
🔇 Additional comments (7)
docs/nemo-guardrails-plugin/configuration.mdx (1)
228-234: LGTM!crates/python/src/lib.rs (1)
30-54: LGTM!Also applies to: 80-91, 131-152, 170-172
crates/python/embedded_python/_guardrails_local.py (1)
25-25: LGTM!Also applies to: 78-91
crates/python/tests/coverage/coverage_tests.rs (4)
48-50: LGTM!Also applies to: 122-148
326-330: LGTM!Also applies to: 350-350, 423-423
479-557: LGTM!
574-578: LGTM!Also applies to: 615-615, 713-713
willkill07
left a comment
There was a problem hiding this comment.
The new shape looks great!
I just realized a core issue that we have:
The plugin config and enablement is under core but the logic for the guardrails plugin is all under Python. We can't have this split.
I'm okay with core getting an added PyO3 dependency (add a new feature named python and default to enabled).
Then we can gate the "local" config on the python feature.
I know this is extra churn, but I'm not sure how else we could get it to work in a deployed scenario with the core Relay library (or just the CLI)
…nt-local-python-backed-backend-for-built-in-nemo' into guardrails-cli-local-test # Conflicts: # crates/core/src/plugins/nemo_guardrails/local.rs # crates/python/tests/coverage/coverage_tests.rs
|
/ok to test 0260c7e |
Signed-off-by: Alex Fournier <afournier@nvidia.com>
|
/ok to test 4aee554 |
|
/ok to test 0260c7e |
@willkill07, there was an error processing your request: See the following link for more information: https://docs.gha-runners.nvidia.com/cpr/e/2/ |
|
/ok to test 4aee554 |
…acked-backend-for-built-in-nemo Signed-off-by: Will Killian <2007799+willkill07@users.noreply.github.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
|
/ok to test aba629c |
Signed-off-by: Will Killian <wkillian@nvidia.com>
|
/ok to test cdbd1a0 |
Signed-off-by: Will Killian <wkillian@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 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 `@crates/core/src/plugins/nemo_guardrails/local_worker.py`:
- Around line 235-241: The per-stream queue is unbounded and allows stdin
ingestion to outrun the consumer; change the queue creation to a bounded
asyncio.Queue by supplying a maxsize (e.g., STREAM_QUEUE_MAXSIZE or a small
integer) when creating the queue for a request_id (the place that currently
calls asyncio.Queue()) so that await queue.put(...) in the "stream_text" branch
will block when the consumer (worker.monitor_stream) is behind; apply the same
change to the other occurrence around lines 257-265 and leave the call to
asyncio.create_task(worker.monitor_stream(request_id, ...)) unchanged so
backpressure is enforced by the bounded queue.
In `@crates/core/src/plugins/nemo_guardrails/python.rs`:
- Around line 898-913: The code currently sends a provider delta into chunk_tx
before the guardrails check runs, so the client can receive blocked text; to
fix, delay sending to chunk_tx until after the worker/guardrail has seen the
text and blocked_message(&blocked) has been evaluated (i.e., send to text_tx
first and await the monitor/verdict), then if blocked_message returns None
forward the chunk via chunk_tx, otherwise send
Err(streaming_output_blocked(...)) to chunk_tx and None to text_tx and await
monitor; reference chunk_tx, text_tx, monitor, blocked_message, and
streaming_output_blocked to locate and reorder this logic or make the worker the
authoritative source of streamed output.
In `@crates/python/src/lib.rs`:
- Around line 64-73: Add a doc comment above install_native_module_alias
explaining the dual-registration strategy: register the native module in
sys.modules (modules.set_item) so imports like "from nemo_relay._native import
..." work, and also attempt to attach it as an attribute on the imported package
(package.setattr("_native", m)) so attribute-style access like
"nemo_relay._native_scope_stack_active()" works; explicitly state that setattr
errors are intentionally ignored because the package may not be importable or
fully initialized during some startup phases, so failure to set the attribute is
non-fatal.
In `@crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs`:
- Around line 136-150: The current check_sequence_guardrails() returns a PASSED
on the LLM output leg so the test never exercises non-streaming output
modifications; change the second element returned by self._check_results in
check_sequence_guardrails() from Result(RailStatus.PASSED) to a
Result(RailStatus.MODIFIED, content="sanitized assistant" or similar) or a
blocking Result, and then update the corresponding test to call llm.execute
(non-streaming) and assert that the Python API surfaces the modification/block
(e.g., the returned object indicates modified/blocked and contains the provided
content), ensuring the test verifies the output-rail branch of the local
backend.
- Around line 223-305: Tests must run serially and always clean up even if f
panics: add a file-local static Mutex (e.g., via
once_cell::sync::Lazy<Mutex<()>>) and acquire its lock at the start of helpers
to serialize tests, and change with_event_loop and
with_isolated_nemo_relay_modules to ensure cleanup runs in a finally path by
using catch_unwind(AssertUnwindSafe(...)) around f, performing restoring actions
(reset event loop/policy via asyncio.set_event_loop(py.None()),
event_loop.close(), clear_nemo_relay_modules, restore saved sys.modules entries,
and call reset_runtime_state()) before re-resuming the panic
(std::panic::resume_unwind) or returning the value; reference functions:
with_isolated_nemo_relay_modules, clear_nemo_relay_modules, with_event_loop, and
reset_runtime_state.
- Around line 41-59: The test helper currently shells out to a hardcoded
"python3" in write_python_wrapper, which can invoke a different interpreter than
PyO3's; update new (fn new(_py: Python<'_>, ...)) to capture the active
interpreter path by evaluating sys.executable from the provided Python<'_>
(`py.run` or `py.eval`) and pass that executable path into write_python_wrapper
(or change write_python_wrapper to accept an executable arg and use it when
generating the wrapper); apply the same change to the other wrapper variant
referenced around lines 185-216 so both wrappers use sys.executable from the
PyO3 runtime instead of "python3".
In `@docs/nemo-guardrails-plugin/about.mdx`:
- Around line 53-55: Update the documentation text for the `local` backend to
state the exact required nemoguardrails package version: change the sentence
mentioning "tested `nemoguardrails` dependency" (the line describing the `local`
backend and `python3 >= 3.11`) to explicitly require "nemoguardrails==0.22.0"
(e.g., "requires python3 >= 3.11 and nemoguardrails==0.22.0"), so readers know
which package/version to install.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: b1252090-fe69-4727-9f1e-a2b8a21c93b9
📒 Files selected for processing (17)
Cargo.tomlcrates/cli/src/config.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/Cargo.tomlcrates/core/src/plugins/nemo_guardrails/component.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/core/src/plugins/nemo_guardrails/python.rscrates/core/tests/unit/observability/atof_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/python/Cargo.tomlcrates/python/src/lib.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rsdocs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Check / Run
🧰 Additional context used
📓 Path-based instructions (34)
{docs/**,README.md,CONTRIBUTING.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Usejust docsfor docs-site builds andjust docs-linkcheckwhen links changed
Run docs site build withjust docs
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run docs link validation with
just docs-linkcheckwhen links change
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify README and docs entry points still match current package names and paths for large or public-facing changes
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,examples/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify examples still run with documented commands for large or public-facing changes
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes
Files:
docs/about-nemo-relay/concepts/plugins.mdxCargo.tomldocs/nemo-guardrails-plugin/about.mdxcrates/python/Cargo.tomlcrates/core/Cargo.tomldocs/nemo-guardrails-plugin/configuration.mdx
**/*.{md,mdx,py,sh,yaml,yml,toml,json}
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Keep package names, repo references, and build commands current
Files:
docs/about-nemo-relay/concepts/plugins.mdxCargo.tomldocs/nemo-guardrails-plugin/about.mdxcrates/python/Cargo.tomlcrates/core/Cargo.tomlcrates/core/src/plugins/nemo_guardrails/local_worker.pydocs/nemo-guardrails-plugin/configuration.mdx
**/*.mdx
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.
MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
**/*.{html,md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in HTML and Markdown files using HTML comment syntax
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
docs/**/*.{md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
docs/**
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run
just docsor./scripts/build-docs.sh htmlto regenerate ignored Fern API reference pages before validation for documentation site changes
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}
⚙️ CodeRabbit configuration file
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings.
Flag stale examples, missing SPDX headers where required, and instructions that no longer match CI or pre-commit behavior.
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # P...
Files:
docs/about-nemo-relay/concepts/plugins.mdxCargo.tomlcrates/core/tests/unit/observability/atof_tests.rsdocs/nemo-guardrails-plugin/about.mdxcrates/python/Cargo.tomlcrates/cli/src/config.rscrates/core/Cargo.tomlcrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/cli/tests/coverage/plugins_tests.rsdocs/nemo-guardrails-plugin/configuration.mdxcrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
Cargo.tomlcrates/core/tests/unit/observability/atof_tests.rscrates/python/Cargo.tomlcrates/cli/src/config.rscrates/core/Cargo.tomlcrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
Cargo.tomlcrates/core/tests/unit/observability/atof_tests.rscrates/python/Cargo.tomlcrates/cli/src/config.rscrates/core/Cargo.tomlcrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.{py,txt,toml,cfg,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Python package names and top-level module imports during coordinated rename operations
Files:
Cargo.tomlcrates/python/Cargo.tomlcrates/core/Cargo.tomlcrates/core/src/plugins/nemo_guardrails/local_worker.py
**/Cargo.toml
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update WebAssembly crate names and generated package names during coordinated rename operations
Confirm or infer the target release version from
upstream/main:Cargo.toml. Derive the release branch asrelease/<major>.<minor>.
Files:
Cargo.tomlcrates/python/Cargo.tomlcrates/core/Cargo.toml
Cargo.toml
📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)
Cargo.toml: MaintainCargo.toml[workspace.package].versionas the source of truth for Rust workspace and Python build versioning
KeepCargo.toml[workspace.dependencies]self-references aligned when the workspace version changes
Files:
Cargo.toml
**/*.toml
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in TOML configuration files using hash comment syntax
Files:
Cargo.tomlcrates/python/Cargo.tomlcrates/core/Cargo.toml
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
Cargo.tomlcrates/core/tests/unit/observability/atof_tests.rscrates/python/Cargo.tomlcrates/cli/src/config.rscrates/core/Cargo.tomlcrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/core/tests/unit/observability/atof_tests.rscrates/cli/src/config.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
crates/core/tests/unit/observability/atof_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/core/tests/unit/observability/atof_tests.rscrates/cli/src/config.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/core/tests/unit/observability/atof_tests.rscrates/core/Cargo.tomlcrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
crates/core/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
If the change touched
crates/coreor shared runtime semantics, also usevalidate-changefor broader validation
crates/core/**/*.rs: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/tests/unit/observability/atof_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
crates/{core,adaptive}/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly
Files:
crates/core/tests/unit/observability/atof_tests.rscrates/core/Cargo.tomlcrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/core/tests/unit/observability/atof_tests.rscrates/cli/src/config.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/core/tests/unit/observability/atof_tests.rscrates/cli/src/config.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
crates/{core,adaptive}/**/*.rs
⚙️ CodeRabbit configuration file
crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.
Files:
crates/core/tests/unit/observability/atof_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/core/tests/unit/observability/atof_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
crates/{python,ffi,node,wasm}/**/*
⚙️ CodeRabbit configuration file
crates/{python,ffi,node,wasm}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.
Files:
crates/python/Cargo.tomlcrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/python/src/lib.rs
**/*config*.{rs,ts,py,go,js,json,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Ensure dynamic config shape still matches the documented canonical model
Files:
crates/cli/src/config.rs
crates/python/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
If the native Rust bridge changed, add the Rust crate tests for
nemo-relay-python
Files:
crates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/python/src/lib.rs
{pyproject.toml,**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Python package names in
pyproject.tomland import paths used throughout the codebase
Files:
crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.py
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*.py: Run Python formatting withuv run ruff format python
Run Python testing withuv run pytest -k "<pattern>"
**/*.py: Use Ruff with rule sets E, F, W, I for Python linting
Use Ruff formatter with line length 120 and double quotes for Python code formatting
Runtyfor Python type checking
Use Python snake_case naming convention for Python identifiers
Include SPDX license header in all Python source files using hash comment syntax
Validate Python code withuv run pre-commit run --all-filesto enforce Ruff linting and formatting, and ty type checking
Files:
crates/core/src/plugins/nemo_guardrails/local_worker.py
🧠 Learnings (58)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**} : Maintain consistent plugin lifecycle across all language bindings (Python, Go, Node/WebAssembly, and Rust)
📚 Learning: 2026-05-26T21:03:12.012Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/review-doc-style/SKILL.md:0-0
Timestamp: 2026-05-26T21:03:12.012Z
Learning: Keep documentation aligned with current NeMo Relay behavior, repo layout, and entry points
Applied to files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**} : Maintain consistent plugin lifecycle across all language bindings (Python, Go, Node/WebAssembly, and Rust)
Applied to files:
docs/about-nemo-relay/concepts/plugins.mdxCargo.tomlcrates/python/Cargo.tomlcrates/core/src/plugins/nemo_guardrails/local.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-26T21:03:12.012Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/review-doc-style/SKILL.md:0-0
Timestamp: 2026-05-26T21:03:12.012Z
Learning: Applies to **/README.md|docs/index.md|python/nemo_relay/README.md|crates/*/README.md : Public behavior changes must be reflected in corresponding entry-point documentation (Must-Fix)
Applied to files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxcrates/cli/src/config.rsdocs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**} : Keep plugin context surfaces aligned across all language implementations
Applied to files:
docs/about-nemo-relay/concepts/plugins.mdxcrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:51:50.794Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/update-project-version/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:50.794Z
Learning: Applies to Cargo.toml : Keep `Cargo.toml` `[workspace.dependencies]` self-references aligned when the workspace version changes
Applied to files:
Cargo.tomlcrates/python/Cargo.toml
📚 Learning: 2026-05-21T22:51:50.794Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/update-project-version/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:50.794Z
Learning: Applies to Cargo.toml : Maintain `Cargo.toml` `[workspace.package].version` as the source of truth for Rust workspace and Python build versioning
Applied to files:
Cargo.tomlcrates/python/Cargo.toml
📚 Learning: 2026-05-21T22:51:21.017Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-python-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:21.017Z
Learning: If any Rust files changed as part of the Python work, also run `cargo fmt --all`, `just test-rust`, and `cargo clippy --workspace --all-targets -- -D warnings`
Applied to files:
Cargo.tomlcrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
📚 Learning: 2026-05-21T22:49:17.713Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-packaging/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:17.713Z
Learning: Applies to **/{Cargo.toml,**/*.rs} : Maintain consistency between Rust package names in `Cargo.toml` and their actual usage across the codebase
Applied to files:
Cargo.toml
📚 Learning: 2026-05-21T22:49:46.956Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/rename-surfaces/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:46.956Z
Learning: Applies to **/*.{rs,toml} : Update Rust crate names and module prefixes during coordinated rename operations
Applied to files:
Cargo.tomlcrates/cli/src/config.rs
📚 Learning: 2026-05-21T22:49:46.956Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/rename-surfaces/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:46.956Z
Learning: Applies to **/Cargo.toml : Update WebAssembly crate names and generated package names during coordinated rename operations
Applied to files:
Cargo.toml
📚 Learning: 2026-05-21T22:51:50.794Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/update-project-version/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:50.794Z
Learning: Run `cargo check --workspace` to refresh `Cargo.lock` after workspace package entries change
Applied to files:
Cargo.toml
📚 Learning: 2026-05-21T22:51:04.073Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-go-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:04.073Z
Learning: Applies to **/*.rs : When Rust files changed as part of Go work, also run `cargo fmt --all`, `just test-rust`, and `cargo clippy --workspace --all-targets -- -D warnings`
Applied to files:
Cargo.toml
📚 Learning: 2026-05-21T22:51:50.794Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/update-project-version/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:50.794Z
Learning: Do not forget to update `Cargo.lock`, `ATTRIBUTIONS-Rust.md`, and `ATTRIBUTIONS-Node.md` after changing versioned inputs that feed them
Applied to files:
Cargo.toml
📚 Learning: 2026-05-21T22:49:35.949Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/prepare-pr/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:35.949Z
Learning: Applies to **/*.rs : Any Rust change must run `cargo clippy --workspace --all-targets -- -D warnings`
Applied to files:
Cargo.toml
📚 Learning: 2026-05-21T22:51:21.017Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-python-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:21.017Z
Learning: Applies to crates/python/**/*.rs : If the native Rust bridge changed, add the Rust crate tests for `nemo-relay-python`
Applied to files:
Cargo.tomlcrates/python/Cargo.tomlcrates/core/Cargo.tomlcrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/python/src/lib.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-29T21:25:49.977Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-29T21:25:49.977Z
Learning: Applies to python/nemo_relay/**/*.py : Python wrapper modules live under `python/nemo_relay/`; the native extension is built from `crates/python` with `maturin`.
Applied to files:
Cargo.tomlcrates/python/Cargo.tomlcrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/python/src/lib.rsdocs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to {crates/python/src/py_api/**/*.rs,python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi} : Update Python native binding in `crates/python/src/py_api/mod.rs` with Python wrapper docstring in `python/nemo_relay/<module>.py` and type stubs in `python/nemo_relay/*.pyi` modules
Applied to files:
Cargo.tomlcrates/python/Cargo.tomlcrates/core/Cargo.tomlcrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/python.rs
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**,python/nemo_relay/adaptive.py,python/nemo_relay/plugin.py,go/nemo_relay/adaptive/**,go/nemo_relay/!(adaptive)/**,**/node/**,**/wasm/**} : Keep adaptive surface in sync across crates/adaptive, shared plugin behavior in core and bindings, Python adaptive/plugin wrappers in python/nemo_relay/adaptive.py and python/nemo_relay/plugin.py, Go adaptive helpers under go/nemo_relay/adaptive plus shared plugin helpers in go/nemo_relay, and Node/WebAssembly adaptive helpers and plugin wrappers
Applied to files:
Cargo.tomlcrates/python/Cargo.tomlcrates/python/src/lib.rs
📚 Learning: 2026-05-21T22:47:48.663Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-integration/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:48.663Z
Learning: Applies to **/*.{py} : Keep `nemo_relay` as an optional dependency and ensure framework behavior falls back cleanly when NeMo Relay is unavailable
Applied to files:
Cargo.tomlcrates/python/Cargo.tomlcrates/python/src/lib.rsdocs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:51:34.986Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-wasm-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:34.986Z
Learning: Applies to crates/wasm/**/*.rs : Run `cargo test -p nemo-relay-wasm` when Rust-only WebAssembly helpers changed
Applied to files:
Cargo.tomlcrates/python/Cargo.tomlcrates/core/Cargo.tomlcrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-27T02:34:30.939Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2026-05-27T02:34:30.939Z
Learning: Applies to crates/ffi/nemo_relay.h : Ensure FFI header sync for `crates/ffi/nemo_relay.h` through Cargo/build.rs
Applied to files:
Cargo.tomlcrates/python/Cargo.tomlcrates/python/src/lib.rs
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to crates/ffi/src/api/**/*.rs : Use `nemo_relay_` prefix for C FFI function names (e.g., `nemo_relay_tool_call`)
Applied to files:
Cargo.tomlcrates/python/Cargo.tomlcrates/python/src/lib.rs
📚 Learning: 2026-05-21T22:48:57.484Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-observability/SKILL.md:0-0
Timestamp: 2026-05-21T22:48:57.484Z
Learning: Applies to crates/core/src/observability/{atif,otel,openinference}.rs : When changing event fields in ATIF, OpenTelemetry, or OpenInference observability surfaces, keep the core event model in `crates/core/src/observability/atif.rs`, `crates/core/src/observability/otel.rs`, and `crates/core/src/observability/openinference.rs` in sync
Applied to files:
crates/core/tests/unit/observability/atof_tests.rs
📚 Learning: 2026-05-29T21:25:49.977Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-29T21:25:49.977Z
Learning: Events use ATOF `0.1` as the canonical event format. Scope events use start/end pairs; mark events record runtime checkpoints.
Applied to files:
crates/core/tests/unit/observability/atof_tests.rs
📚 Learning: 2026-05-21T22:48:57.484Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-observability/SKILL.md:0-0
Timestamp: 2026-05-21T22:48:57.484Z
Learning: When event fields change, run Rust crate tests and execute `just test-rust` to validate the affected observability modules
Applied to files:
crates/core/tests/unit/observability/atof_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-26T21:03:12.012Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/review-doc-style/SKILL.md:0-0
Timestamp: 2026-05-26T21:03:12.012Z
Learning: Applies to **/README.md|docs/index.md|python/nemo_relay/README.md|crates/*/README.md : Update entry-point documentation (README.md, docs/index.md, package/crate READMEs, and binding-level source READMEs) whenever public behavior changes
Applied to files:
docs/nemo-guardrails-plugin/about.mdxcrates/cli/src/config.rscrates/python/src/lib.rsdocs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:50:43.254Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/small-fix/SKILL.md:0-0
Timestamp: 2026-05-21T22:50:43.254Z
Learning: Update documentation if public behavior changed
Applied to files:
docs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to {README.md,docs/getting-started/**/*.md} : Update `README.md`, `docs/getting-started/`, or binding-level READMEs if behavior differs by language or usage changed
Applied to files:
docs/nemo-guardrails-plugin/about.mdx
📚 Learning: 2026-05-26T21:03:12.012Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/review-doc-style/SKILL.md:0-0
Timestamp: 2026-05-26T21:03:12.012Z
Learning: Apply this skill when reviewing docs-only changes, example-heavy changes, or any public-facing text update that should be checked against NVIDIA style guidance and NeMo Relay repo conventions.
Applied to files:
docs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to crates/ffi/src/api/**/*.rs : Add or update FFI wrappers in relevant `crates/ffi/src/api/*.rs` modules, re-export through `crates/ffi/src/api/mod.rs`, and ensure generated `crates/ffi/nemo_relay.h` stays correct
Applied to files:
crates/python/Cargo.tomlcrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/python/src/lib.rscrates/cli/tests/coverage/plugins_tests.rs
📚 Learning: 2026-05-21T22:47:20.312Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/README.md:0-0
Timestamp: 2026-05-21T22:47:20.312Z
Learning: Use this directory for maintainer-only skill set for developing NeMo Relay itself, including core API changes, patch maintenance, packaging, CI, documentation, middleware and observability internals, and library validation across bindings
Applied to files:
crates/python/Cargo.tomldocs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-29T21:25:49.977Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-29T21:25:49.977Z
Learning: Applies to crates/node/**/*.{js,ts,tsx} : Node.js public entry points include the main runtime package plus `nemo-relay-node/typed`, `nemo-relay-node/plugin`, and `nemo-relay-node/adaptive`.
Applied to files:
crates/python/Cargo.toml
📚 Learning: 2026-05-27T02:34:30.939Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2026-05-27T02:34:30.939Z
Learning: Applies to **/README.md : Update relevant crate or package README when that surface changed
Applied to files:
crates/cli/src/config.rs
📚 Learning: 2026-05-21T22:52:14.330Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/validate-change/SKILL.md:0-0
Timestamp: 2026-05-21T22:52:14.330Z
Learning: Applies to {docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md} : Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes
Applied to files:
crates/cli/src/config.rs
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to crates/wasm/src/api/**/*.rs : Update WebAssembly binding in `crates/wasm/src/api/mod.rs` for language-native bindings
Applied to files:
crates/cli/src/config.rscrates/python/src/lib.rs
📚 Learning: 2026-05-21T22:50:51.194Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-ffi-surface/SKILL.md:0-0
Timestamp: 2026-05-21T22:50:51.194Z
Learning: Applies to **/*.rs : Run `just test-rust` to validate FFI changes
Applied to files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/cli/tests/coverage/plugins_tests.rs
📚 Learning: 2026-05-29T21:25:49.977Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-29T21:25:49.977Z
Learning: Run tests for every language affected by a change. If you touch the Rust core runtime, middleware semantics, event shape, scope behavior, typed codecs, plugins, or observability, expect to validate every affected binding because the bindings share the same runtime contract.
Applied to files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:51:27.841Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-rust-core/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:27.841Z
Learning: Use narrower crate tests as a local debug loop, not as the final validation story for Rust changes
Applied to files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-27T02:34:30.939Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2026-05-27T02:34:30.939Z
Learning: Run all affected language test targets (`just test-rust`, `just test-python`, `just test-go`, `just test-node`, `just test-wasm`) when changes touch the core Rust crate since all bindings depend on it
Applied to files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
📚 Learning: 2026-05-21T22:49:35.949Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/prepare-pr/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:35.949Z
Learning: Applies to **/*.rs : Any Rust change must run `just test-rust`
Applied to files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
📚 Learning: 2026-05-21T22:52:14.330Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/validate-change/SKILL.md:0-0
Timestamp: 2026-05-21T22:52:14.330Z
Learning: For core runtime or shared semantics changes, use `test-rust-core` which includes Rust testing, formatting, linting, and full cross-language matrix
Applied to files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/cli/tests/coverage/plugins_tests.rs
📚 Learning: 2026-05-21T22:47:58.898Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-middleware/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:58.898Z
Learning: Applies to crates/core/src/api/registry.rs : Use existing `global_*_registry_api!` and `scope_*_registry_api!` macro patterns in `crates/core/src/api/registry.rs` for both global and scope-local registration APIs unless design explicitly rules one out
Applied to files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/src/plugins/nemo_guardrails/component.rs
📚 Learning: 2026-05-21T22:47:58.898Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-middleware/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:58.898Z
Learning: Applies to crates/core/src/api/runtime/state.rs : Add registry fields as `SortedRegistry<GuardrailEntry<T>>` or `SortedRegistry<Intercept<T>>` to `NemoRelayContextState` in `crates/core/src/api/runtime/state.rs`
Applied to files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:47:58.898Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-middleware/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:58.898Z
Learning: Applies to crates/core/src/api/runtime/state.rs : Add chain execution helpers to `NemoRelayContextState` following the pattern of existing methods like `tool_sanitize_request_chain` or `tool_request_intercepts_chain`
Applied to files:
crates/python/tests/coverage/nemo_guardrails_coverage_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:51:04.073Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-go-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:04.073Z
Learning: Applies to crates/core/**/*.rs : If the change touched `crates/core` or shared runtime semantics, also use `validate-change` for broader validation
Applied to files:
crates/core/src/plugins/nemo_guardrails/component.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to crates/node/src/api/**/*.rs : Update Node.js binding in `crates/node/src/api/mod.rs` for language-native bindings
Applied to files:
crates/python/src/lib.rs
📚 Learning: 2026-05-27T02:34:30.939Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2026-05-27T02:34:30.939Z
Learning: Applies to crates/ffi/*.h : Prefix C FFI exports with `nemo_relay_`
Applied to files:
crates/python/src/lib.rs
📚 Learning: 2026-05-21T22:47:48.663Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-integration/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:48.663Z
Learning: Applies to **/*.{py} : Optional import/activation guard must be in place for the framework integration
Applied to files:
crates/python/src/lib.rs
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {python/nemo_relay/adaptive.py,python/nemo_relay/plugin.py,go/nemo_relay/adaptive/**,**/node/adaptive/**,**/wasm/adaptive/**} : Ensure typed helper constructors still map cleanly to the same config document in adaptive bindings across Python, Go, Node, and WebAssembly
Applied to files:
crates/python/src/lib.rs
📚 Learning: 2026-05-21T22:51:04.073Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-go-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:04.073Z
Learning: Applies to crates/ffi/**/*.rs : If the change touched `crates/ffi`, also use `test-ffi-surface` for validation
Applied to files:
crates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:49:17.713Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-packaging/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:17.713Z
Learning: Applies to RELEASING.md : Ensure public packaging changes are reflected in release-facing documentation and RELEASING.md
Applied to files:
docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:47:48.663Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-integration/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:48.663Z
Learning: Applies to **/*.{py} : LLM calls should use NeMo Relay managed execution where possible
Applied to files:
docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:47:48.663Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-integration/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:48.663Z
Learning: Applies to **/*.{py} : Tool calls should use NeMo Relay managed execution where possible
Applied to files:
docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:48:28.092Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/contribute-integration/SKILL.md:0-0
Timestamp: 2026-05-21T22:48:28.092Z
Learning: Preserve the framework's original behavior when NeMo Relay is absent
Applied to files:
docs/nemo-guardrails-plugin/configuration.mdx
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**} : Maintain documented and tested validation and report behavior for adaptive surfaces
Applied to files:
crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:51:34.986Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-wasm-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:34.986Z
Learning: If the change touched shared runtime semantics in `crates/core` or `crates/adaptive`, also use the `validate-change` skill
Applied to files:
crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
📚 Learning: 2026-05-21T22:51:27.841Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-rust-core/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:27.841Z
Learning: Run `just test-rust` as the primary Rust testing command for shared runtime
Applied to files:
crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
🪛 Ruff (0.15.15)
crates/core/src/plugins/nemo_guardrails/local_worker.py
[warning] 33-33: Missing type annotation for **fields
(ANN003)
[warning] 62-62: Do not catch blind exception: Exception
(BLE001)
[warning] 73-73: Missing return type annotation for special method __init__
Add return type annotation: None
(ANN204)
[warning] 76-76: Missing return type annotation for special method __aiter__
(ANN204)
[warning] 79-79: Missing return type annotation for special method __anext__
(ANN204)
[warning] 87-87: Missing return type annotation for special method __init__
Add return type annotation: None
(ANN204)
[warning] 88-88: Version block is outdated for minimum Python version
Remove outdated version block
(UP036)
[warning] 89-89: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 98-102: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 109-109: Missing return type annotation for private function _import_dependency
(ANN202)
[warning] 115-118: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 119-122: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 124-124: Missing return type annotation for private function _build_guardrails_config
(ANN202)
[warning] 131-131: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 137-137: Missing return type annotation for private function _rail_kind
(ANN202)
[warning] 142-142: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 167-170: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 173-176: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 178-178: Missing return type annotation for private function _output_rails_config
(ANN202)
[warning] 197-197: Do not catch blind exception: Exception
(BLE001)
[warning] 207-207: Too many branches (14 > 12)
(PLR0912)
[warning] 208-208: Using the global statement to update worker is discouraged
(PLW0603)
[warning] 223-223: Abstract raise to an inner function
(TRY301)
[warning] 223-223: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 237-237: Store a reference to the return value of asyncio.create_task
(RUF006)
[warning] 247-247: Abstract raise to an inner function
(TRY301)
[warning] 247-247: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 248-248: Do not catch blind exception: Exception
(BLE001)
[warning] 262-262: Do not catch blind exception: Exception
(BLE001)
[warning] 265-265: Store a reference to the return value of asyncio.create_task
(RUF006)
Signed-off-by: Will Killian <wkillian@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (3)
crates/core/src/plugins/nemo_guardrails/python.rs (2)
898-913:⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy liftDon't emit a delta before the rail verdict for that delta is known.
After
text_tx.send(Some(text)),yield_now()only gives the monitor a chance to run; it does not wait for the Python worker to approve that text. The same delta can still be forwarded on Line 913 before a later"blocked"event arrives, which leaks output thatstream_first = trueis supposed to suppress. Buffer the provider chunk until the worker has definitively cleared it, or make the worker the source of streamed output.🤖 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 `@crates/core/src/plugins/nemo_guardrails/python.rs` around lines 898 - 913, The code currently sends chunk_tx(Ok(chunk)) before the guardrail verdict can arrive; after sending text_tx.send(Some(text)) replace the yield_now-based check with a deterministic wait for the monitor/verdict: do not call chunk_tx.send(Ok(chunk)) until the monitor has processed the text and blocked_message(&blocked) is confirmed absent (or until the monitor explicitly signals approval); use the existing monitor/blocked state (monitor.await or a monitor-provided approval signal) and the blocked_message(&blocked) check (and keep finish_stream_monitor/streaming_output_blocked handling) so the provider chunk is buffered and only forwarded when the guardrail has definitively cleared it.
462-469:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAdd a timeout to non-init worker RPCs.
request()waits onreceiver.recv()forever. If the Python subprocess hangs insidecheck_asyncorstream_asyncwithout exiting, intercepted LLM/tool calls wedge indefinitely and the shared worker never gets recycled. Bound this wait and tear down the worker on expiry so calls fail predictably.🤖 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 `@crates/core/src/plugins/nemo_guardrails/python.rs` around lines 462 - 469, request() currently blocks forever on receiver.recv(); wrap the recv() call in a tokio::time::timeout (use a sensible constant like WORKER_RPC_TIMEOUT or make it configurable) so non-init worker RPCs fail after the deadline, map the timeout to a FlowError::Internal (or appropriate FlowError) and ensure you tear down the worker on expiry (invoke the worker shutdown/cleanup path you already have for terminating stalled workers or call the worker teardown method/logic after timeout before returning), keeping the rest of the flow (send_request, envelope handling and worker_result(envelope)) intact.crates/core/src/plugins/nemo_guardrails/local_worker.py (1)
236-242:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftBounded queues here still don't restore end-to-end backpressure.
STREAM_QUEUE_MAXSIZEcapsstreams[request_id], butmain()still keeps reading stdin and spawning detachedhandle_message()tasks for everystream_text. Once a stream falls behind, the backlog moves from the queue into pending tasks and retained JSON lines instead of applying backpressure to stdin ingestion. Processstream_*messages inline, or otherwise gate reads on per-stream capacity, so long/stalled streams cannot grow memory without bound.Also applies to: 256-266
🤖 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 `@crates/core/src/plugins/nemo_guardrails/local_worker.py` around lines 236 - 242, Bounded per-stream queues (STREAM_QUEUE_MAXSIZE) don't stop stdin from being read because main() spawns detached handle_message() tasks for every incoming "stream_text", letting backlog accumulate in tasks/JSON; instead, gate reads by making stream messages processed inline or by using awaitable backpressure on the per-stream queue. Change main() and handle_message() so that when command is "stream_text" you do an await on streams[request_id].put(text) (or await handle_message(...) directly) rather than creating a detached asyncio.create_task; keep monitor_stream(request_id, ...) unchanged but ensure streams.get(request_id) is checked and awaited (blocking) when full so stalled streams naturally apply backpressure to stdin and prevent unbounded memory growth.
🤖 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 `@crates/core/src/plugins/nemo_guardrails/python.rs`:
- Around line 678-688: The parse_check_result function currently treats any
status other than "blocked" or "modified" as Passed; change this to explicitly
accept "passed" and reject unknown statuses by returning a FlowError::Internal.
In the match on result.status (in parse_check_result), add an explicit "passed"
arm that returns Ok(LocalCheckOutcome::Passed) and replace the wildcard arm with
an Err(FlowError::Internal(...)) that includes the unexpected status string
(e.g., format!("unexpected worker check status: {}", result.status)). This
ensures WorkerCheckResult (and function parse_check_result) only accepts
"blocked", "modified", or "passed" and fails closed for any other value.
- Around line 541-552: LocalGuardrailsWorker::write_command currently performs
blocking writes and flushes synchronously on Tokio worker threads (called from
request → send_request and from monitor_guardrails_stream →
send_stream_text/send_stream_end), which can block the runtime; refactor so
writes run off the async tokio tasks: create a dedicated blocking writer (e.g.,
spawn a std::thread that owns the child stdin and a channel) and add a sender
field to LocalGuardrailsWorker; change write_command to serialize the Json and
send it over the channel (returning errors if the channel is closed), perform
the actual writeln!/flush() inside the dedicated writer thread and translate I/O
errors back into FlowError; ensure proper shutdown/flush when the worker is
dropped or the channel is closed.
---
Duplicate comments:
In `@crates/core/src/plugins/nemo_guardrails/local_worker.py`:
- Around line 236-242: Bounded per-stream queues (STREAM_QUEUE_MAXSIZE) don't
stop stdin from being read because main() spawns detached handle_message() tasks
for every incoming "stream_text", letting backlog accumulate in tasks/JSON;
instead, gate reads by making stream messages processed inline or by using
awaitable backpressure on the per-stream queue. Change main() and
handle_message() so that when command is "stream_text" you do an await on
streams[request_id].put(text) (or await handle_message(...) directly) rather
than creating a detached asyncio.create_task; keep monitor_stream(request_id,
...) unchanged but ensure streams.get(request_id) is checked and awaited
(blocking) when full so stalled streams naturally apply backpressure to stdin
and prevent unbounded memory growth.
In `@crates/core/src/plugins/nemo_guardrails/python.rs`:
- Around line 898-913: The code currently sends chunk_tx(Ok(chunk)) before the
guardrail verdict can arrive; after sending text_tx.send(Some(text)) replace the
yield_now-based check with a deterministic wait for the monitor/verdict: do not
call chunk_tx.send(Ok(chunk)) until the monitor has processed the text and
blocked_message(&blocked) is confirmed absent (or until the monitor explicitly
signals approval); use the existing monitor/blocked state (monitor.await or a
monitor-provided approval signal) and the blocked_message(&blocked) check (and
keep finish_stream_monitor/streaming_output_blocked handling) so the provider
chunk is buffered and only forwarded when the guardrail has definitively cleared
it.
- Around line 462-469: request() currently blocks forever on receiver.recv();
wrap the recv() call in a tokio::time::timeout (use a sensible constant like
WORKER_RPC_TIMEOUT or make it configurable) so non-init worker RPCs fail after
the deadline, map the timeout to a FlowError::Internal (or appropriate
FlowError) and ensure you tear down the worker on expiry (invoke the worker
shutdown/cleanup path you already have for terminating stalled workers or call
the worker teardown method/logic after timeout before returning), keeping the
rest of the flow (send_request, envelope handling and worker_result(envelope))
intact.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: df148fab-30d9-4ef4-8f64-ddfcfe65f9c4
📒 Files selected for processing (14)
crates/cli/src/config.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/core/src/plugins/nemo_guardrails/local.rscrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/core/src/plugins/nemo_guardrails/python.rscrates/core/tests/unit/observability/atof_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/python/src/lib.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rsdocs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (31)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/cli/src/config.rscrates/core/tests/unit/observability/atof_tests.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/cli/src/config.rscrates/core/tests/unit/observability/atof_tests.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/cli/src/config.rscrates/core/tests/unit/observability/atof_tests.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/observability/atof_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/python.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/cli/src/config.rscrates/core/tests/unit/observability/atof_tests.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
crates/core/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
If the change touched
crates/coreor shared runtime semantics, also usevalidate-changefor broader validation
crates/core/**/*.rs: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/observability/atof_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/python.rs
crates/{core,adaptive}/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/observability/atof_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/python.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/cli/src/config.rscrates/core/tests/unit/observability/atof_tests.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/cli/src/config.rscrates/core/tests/unit/observability/atof_tests.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/cli/src/config.rscrates/core/tests/unit/observability/atof_tests.rscrates/python/src/lib.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
crates/{core,adaptive}/**/*.rs
⚙️ CodeRabbit configuration file
crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.
Files:
crates/core/src/plugins/nemo_guardrails/local.rscrates/core/tests/unit/observability/atof_tests.rscrates/core/src/plugins/nemo_guardrails/component.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/python.rs
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # P...
Files:
crates/core/src/plugins/nemo_guardrails/local.rsdocs/about-nemo-relay/concepts/plugins.mdxcrates/cli/src/config.rscrates/core/tests/unit/observability/atof_tests.rscrates/python/src/lib.rsdocs/nemo-guardrails-plugin/about.mdxcrates/core/src/plugins/nemo_guardrails/component.rsdocs/nemo-guardrails-plugin/configuration.mdxcrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
{docs/**,README.md,CONTRIBUTING.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Usejust docsfor docs-site builds andjust docs-linkcheckwhen links changed
Run docs site build withjust docs
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run docs link validation with
just docs-linkcheckwhen links change
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify README and docs entry points still match current package names and paths for large or public-facing changes
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,examples/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify examples still run with documented commands for large or public-facing changes
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
**/*.{md,mdx,py,sh,yaml,yml,toml,json}
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Keep package names, repo references, and build commands current
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdxcrates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.mdx
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.
MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
**/*.{html,md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in HTML and Markdown files using HTML comment syntax
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
docs/**/*.{md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
docs/**
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run
just docsor./scripts/build-docs.sh htmlto regenerate ignored Fern API reference pages before validation for documentation site changes
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}
⚙️ CodeRabbit configuration file
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings.
Flag stale examples, missing SPDX headers where required, and instructions that no longer match CI or pre-commit behavior.
Files:
docs/about-nemo-relay/concepts/plugins.mdxdocs/nemo-guardrails-plugin/about.mdxdocs/nemo-guardrails-plugin/configuration.mdx
**/*config*.{rs,ts,py,go,js,json,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Ensure dynamic config shape still matches the documented canonical model
Files:
crates/cli/src/config.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
crates/core/tests/unit/observability/atof_tests.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/core/tests/unit/observability/atof_tests.rscrates/cli/tests/coverage/plugins_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/tests/unit/plugins/nemo_guardrails/component_tests.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
crates/python/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
If the native Rust bridge changed, add the Rust crate tests for
nemo-relay-python
Files:
crates/python/src/lib.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
crates/{python,ffi,node,wasm}/**/*
⚙️ CodeRabbit configuration file
crates/{python,ffi,node,wasm}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.
Files:
crates/python/src/lib.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rs
{pyproject.toml,**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Python package names in
pyproject.tomland import paths used throughout the codebase
Files:
crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.{py,txt,toml,cfg,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Python package names and top-level module imports during coordinated rename operations
Files:
crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.py
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*.py: Run Python formatting withuv run ruff format python
Run Python testing withuv run pytest -k "<pattern>"
**/*.py: Use Ruff with rule sets E, F, W, I for Python linting
Use Ruff formatter with line length 120 and double quotes for Python code formatting
Runtyfor Python type checking
Use Python snake_case naming convention for Python identifiers
Include SPDX license header in all Python source files using hash comment syntax
Validate Python code withuv run pre-commit run --all-filesto enforce Ruff linting and formatting, and ty type checking
Files:
crates/core/src/plugins/nemo_guardrails/local_worker.py
🪛 Ruff (0.15.15)
crates/core/src/plugins/nemo_guardrails/local_worker.py
[warning] 34-34: Missing type annotation for **fields
(ANN003)
[warning] 63-63: Do not catch blind exception: Exception
(BLE001)
[warning] 74-74: Missing return type annotation for special method __init__
Add return type annotation: None
(ANN204)
[warning] 77-77: Missing return type annotation for special method __aiter__
(ANN204)
[warning] 80-80: Missing return type annotation for special method __anext__
(ANN204)
[warning] 88-88: Missing return type annotation for special method __init__
Add return type annotation: None
(ANN204)
[warning] 89-89: Version block is outdated for minimum Python version
Remove outdated version block
(UP036)
[warning] 90-90: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 99-103: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 110-110: Missing return type annotation for private function _import_dependency
(ANN202)
[warning] 116-119: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 120-123: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 125-125: Missing return type annotation for private function _build_guardrails_config
(ANN202)
[warning] 132-132: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 138-138: Missing return type annotation for private function _rail_kind
(ANN202)
[warning] 143-143: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 168-171: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 174-177: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 179-179: Missing return type annotation for private function _output_rails_config
(ANN202)
[warning] 198-198: Do not catch blind exception: Exception
(BLE001)
[warning] 208-208: Too many branches (14 > 12)
(PLR0912)
[warning] 209-209: Using the global statement to update worker is discouraged
(PLW0603)
[warning] 224-224: Abstract raise to an inner function
(TRY301)
[warning] 224-224: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 238-238: Store a reference to the return value of asyncio.create_task
(RUF006)
[warning] 248-248: Abstract raise to an inner function
(TRY301)
[warning] 248-248: Avoid specifying long messages outside the exception class
(TRY003)
[warning] 249-249: Do not catch blind exception: Exception
(BLE001)
[warning] 263-263: Do not catch blind exception: Exception
(BLE001)
[warning] 266-266: Store a reference to the return value of asyncio.create_task
(RUF006)
🔇 Additional comments (25)
crates/core/src/plugins/nemo_guardrails/component.rs (7)
195-197: LGTM!
332-332: LGTM!
533-533: LGTM!
702-714: LGTM!
977-987: Validation correctly rejectsrequest_defaultsin local mode.The early return when
config.mode == "local"prevents downstream validation from running onrequest_defaultsfields, which is the intended behavior for this unsupported surface.
20-21: LGTM!Also applies to: 25-25
457-457: LGTM!crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs (3)
364-364: LGTM!
765-765: LGTM!Also applies to: 792-797
799-813: Good test coverage for local mode request_defaults rejection.This test validates the validation rule added at component.rs:977-987.
crates/cli/tests/coverage/plugins_tests.rs (2)
202-205: LGTM!
1352-1352: LGTM!Also applies to: 1363-1366
crates/core/src/plugins/nemo_guardrails/local.rs (1)
1-15: LGTM!docs/about-nemo-relay/concepts/plugins.mdx (1)
177-178: LGTM!docs/nemo-guardrails-plugin/about.mdx (3)
23-24: LGTM!
48-54: LGTM!
80-116: LGTM!docs/nemo-guardrails-plugin/configuration.mdx (3)
49-60: LGTM!
220-306: LGTM!
322-352: LGTM!crates/python/src/lib.rs (1)
26-26: LGTM!Also applies to: 67-69
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs (1)
1-339: LGTM!crates/python/tests/coverage/nemo_guardrails_coverage_tests.rs (1)
1-914: LGTM!crates/cli/src/config.rs (1)
161-161: LGTM!crates/core/tests/unit/observability/atof_tests.rs (1)
303-303: LGTM!
Signed-off-by: Will Killian <wkillian@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/core/src/plugins/nemo_guardrails/local_worker.py`:
- Around line 266-269: The create_task call in main that fires handle_message
without keeping the Task (the asyncio.create_task(handle_message(...)) branch)
discards the handle and prevents graceful shutdown/observability; change main to
store created tasks in a module/local set (e.g., pending_tasks), add a done
callback to remove completed tasks, and on stdin-close/shutdown cancel and await
remaining tasks (or await asyncio.gather(*pending_tasks,
return_exceptions=True)) before returning so handle_message tasks are tracked
and cleaned up; keep the stream-handling branch unchanged but ensure both paths
use the same tracking set.
In `@docs/nemo-guardrails-plugin/configuration.mdx`:
- Line 54: The long table cell under the "Managed streaming LLM execution"
comparison is too dense; refactor it to improve readability by either (a)
splitting that single cell into multiple rows with separate cells for remote
HTTP(S) contract support, managed input checks vs Guardrails-native output
streaming, and the note about chunk release behavior and `stream_first = false`
limitation, or (b) simplify the cell to a short summary (e.g., "Supported; see
Streaming behavior section") and move the detailed clauses (provider chunk
release after local rail monitor clears stream, `rails.output.streaming.enabled
= true`, and `stream_first = false` not supported) into a new subsection
elsewhere in the document. Update the "Managed streaming LLM execution" table
row accordingly and add the new subsection referenced from the table if you
choose option (b).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: b9be7bfe-fe3c-4849-9459-c87eb955da13
📒 Files selected for processing (4)
crates/core/src/plugins/nemo_guardrails/local_worker.pycrates/core/src/plugins/nemo_guardrails/python.rscrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rsdocs/nemo-guardrails-plugin/configuration.mdx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (28)
{docs/**,README.md,CONTRIBUTING.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Usejust docsfor docs-site builds andjust docs-linkcheckwhen links changed
Run docs site build withjust docs
Files:
docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run docs link validation with
just docs-linkcheckwhen links change
Files:
docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify README and docs entry points still match current package names and paths for large or public-facing changes
Files:
docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,examples/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify examples still run with documented commands for large or public-facing changes
Files:
docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes
Files:
docs/nemo-guardrails-plugin/configuration.mdx
**/*.{md,mdx,py,sh,yaml,yml,toml,json}
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Keep package names, repo references, and build commands current
Files:
docs/nemo-guardrails-plugin/configuration.mdxcrates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.mdx
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.
MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)
Files:
docs/nemo-guardrails-plugin/configuration.mdx
**/*.{html,md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in HTML and Markdown files using HTML comment syntax
Files:
docs/nemo-guardrails-plugin/configuration.mdx
docs/**/*.{md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed
Files:
docs/nemo-guardrails-plugin/configuration.mdx
docs/**
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run
just docsor./scripts/build-docs.sh htmlto regenerate ignored Fern API reference pages before validation for documentation site changes
Files:
docs/nemo-guardrails-plugin/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}
⚙️ CodeRabbit configuration file
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings.
Flag stale examples, missing SPDX headers where required, and instructions that no longer match CI or pre-commit behavior.
Files:
docs/nemo-guardrails-plugin/configuration.mdx
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # P...
Files:
docs/nemo-guardrails-plugin/configuration.mdxcrates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/python.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/python.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/python.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/python.rs
crates/core/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
If the change touched
crates/coreor shared runtime semantics, also usevalidate-changefor broader validation
crates/core/**/*.rs: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/python.rs
crates/{core,adaptive}/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/python.rscrates/core/src/plugins/nemo_guardrails/local_worker.py
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/python.rs
crates/{core,adaptive}/**/*.rs
⚙️ CodeRabbit configuration file
crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rscrates/core/src/plugins/nemo_guardrails/python.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs
{pyproject.toml,**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Python package names in
pyproject.tomland import paths used throughout the codebase
Files:
crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.{py,txt,toml,cfg,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Python package names and top-level module imports during coordinated rename operations
Files:
crates/core/src/plugins/nemo_guardrails/local_worker.py
**/*.py
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*.py: Run Python formatting withuv run ruff format python
Run Python testing withuv run pytest -k "<pattern>"
**/*.py: Use Ruff with rule sets E, F, W, I for Python linting
Use Ruff formatter with line length 120 and double quotes for Python code formatting
Runtyfor Python type checking
Use Python snake_case naming convention for Python identifiers
Include SPDX license header in all Python source files using hash comment syntax
Validate Python code withuv run pre-commit run --all-filesto enforce Ruff linting and formatting, and ty type checking
Files:
crates/core/src/plugins/nemo_guardrails/local_worker.py
🪛 Ruff (0.15.15)
crates/core/src/plugins/nemo_guardrails/local_worker.py
[warning] 269-269: Store a reference to the return value of asyncio.create_task
(RUF006)
🔇 Additional comments (11)
crates/core/tests/unit/plugins/nemo_guardrails/local_python_tests.rs (1)
297-355: LGTM!docs/nemo-guardrails-plugin/configuration.mdx (5)
23-44: LGTM!
61-219: LGTM!
220-306: LGTM!
307-321: LGTM!
322-351: LGTM!crates/core/src/plugins/nemo_guardrails/python.rs (5)
36-36: LGTM!Also applies to: 463-481
361-363: LGTM!Also applies to: 397-398, 553-577, 585-638
579-583: LGTM!
754-767: LGTM!
949-1034: LGTM!
Signed-off-by: Will Killian <wkillian@nvidia.com>
…acked-backend-for-built-in-nemo
|
/ok to test 8527102 |
Overview
This PR adds the built-in
localbackend for the first-partynemo_guardrailsplugin and updates the shippedremote/localmode boundaries in docs and coverage.The local backend now runs NeMo Guardrails through a
python3subprocess worker instead of embedding Python in the Rust core or CLI binary. That keeps static Linux*-muslpackage builds from linking PyO3/libpython while still supporting local Guardrails checks when a compatible Python runtime is available. The final PR diff does not include anyCargo.tomlchanges.Details
What changed:
crates/coreownership instead of a Python-binding-installed provider pathpython3subprocess workerlocal.python_executable, defaulting toNEMO_RELAY_PYTHONwhen set and otherwisepython3python3 >= 3.11andnemoguardrails==0.22.0input/output, local managedtool_input/tool_output, and local streaming output through Guardrails-nativestream_first = truesemanticsrequest_defaultsandrails.output.streaming.stream_first = falseupstream/mainImportant local-mode boundaries in this PR:
nemoguardrails==0.22.0stream_first = truesemantics, so a later output block can happen after some chunks were already emittedrequest_defaultsrails.output.streaming.stream_first = falsenemo-relayplus upstreamnemoguardrails==0.22.0Validation run:
cargo fmt --allcargo test -p nemo-relay nemo_guardrailscargo test -p nemo-relay-cli nemo_guardrailscargo test -p nemo-relay-python --libcargo test -p nemo-relay --features atof-streaming streaming_endpoints_receive_raw_atof_events_and_file_output_remainscargo tree -p nemo-relay-cli --target x86_64-unknown-linux-musl -e normalwith no PyO3/libpython packages in the CLI graphcargo check -p nemo-relay --no-default-featuresjust test-pythonjust docsuv run pre-commit run --files ...Notes:
cargo check --target x86_64-unknown-linux-musl -p nemo-relay-clicould not complete on macOS because the local machine lacksx86_64-linux-musl-gcc; CI installs musl tools.just test-rustwas stopped after hanging for several minutes in unrelated server/session tests. The Rust CI failures seen after the subprocess change were covered by the focused ATOF and Python-native coverage tests above.Where should the reviewer start?
Start with:
crates/core/src/plugins/nemo_guardrails/python.rscrates/core/src/plugins/nemo_guardrails/local_worker.pycrates/core/src/plugins/nemo_guardrails/component.rscrates/python/tests/coverage/nemo_guardrails_coverage_tests.rsdocs/nemo-guardrails-plugin/configuration.mdxRelated Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)
Summary by CodeRabbit
New Features
Bug Fixes / Validation
Documentation
Tests