Skip to content

feat: implement nemo_guardrails remote backend#144

Open
afourniernv wants to merge 15 commits into
NVIDIA:mainfrom
afourniernv:afournier/nmf-131-remote-backend
Open

feat: implement nemo_guardrails remote backend#144
afourniernv wants to merge 15 commits into
NVIDIA:mainfrom
afourniernv:afournier/nmf-131-remote-backend

Conversation

@afourniernv
Copy link
Copy Markdown
Contributor

@afourniernv afourniernv commented May 21, 2026

Overview

Adds the first real built-in nemo_guardrails remote backend for NeMo Relay core.

This PR moves beyond the contract-only surface and implements the first shippable remote slice:

  • built-in plugin auto-registration in core

  • remote backend activation for mode = remote

  • non-streaming and streaming LLM execution through the Guardrails server

  • managed tool_output execution checks through the same remote backend

  • request-default pass-through for remote Guardrails request semantics

  • explicit validation that stock remote mode does not currently support managed tool_input

  • focused runtime validation and coverage for transport, malformed responses, tool rewrites, and error handling

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

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

Details

  • auto-register the built-in nemo_guardrails plugin through ensure_builtin_plugins_registered()
  • add a dedicated default core feature guardrails-remote for the remote backend dependency path
  • implement the remote Guardrails runtime across:
    • crates/core/src/plugins/nemo_guardrails/component.rs
    • crates/core/src/plugins/nemo_guardrails/remote.rs
  • support the native remote server contract for codec = "openai_chat"
  • support both non-streaming and streaming LLM execution
  • support remote request defaults pass-through:
    • context
    • thread_id
    • state
    • rails
    • llm_params
    • llm_output
    • output_vars
    • log
  • support managed tool_output execution checks via the remote backend
  • reject managed tool_input in stock remote mode with a focused validation error instead of silently leaving it non-enforcing
  • emit coarse backend-level nemo_guardrails.remote.* marks for both LLM and managed tool remote checks
  • precompute stable remote Guardrails payloads during runtime initialization instead of rebuilding them per request
  • split remote runtime coverage into component_tests.rs and remote_tests.rs to keep contract/config tests separate from transport/runtime behavior
  • add focused unit coverage for:
    • built-in registration
    • remote config validation
    • transport and malformed-response lanes
    • non-streaming and streaming remote execution
    • managed tool_output blocking and rewrite behavior
    • tool-only config isolation from LLM execution
    • context/state/thread propagation on managed tool checks

Rail and observability boundary in this PR:

  • Native NeMo Relay-managed surfaces:
    • input
    • output
    • tool_output
  • These are real runtime interception surfaces in NeMo Relay. The built-in plugin installs managed LLM and tool execution behavior around them, and the remote backend can block or rewrite those executions directly.
  • Managed tool_input remains a known NeMo Relay surface, but stock remote mode now rejects it explicitly because the Guardrails remote contract does not currently activate pre-execution tool-call rails from externally submitted chat-completions history.
  • Remote request-time rail pass-through:
    • request_defaults.rails.input
    • request_defaults.rails.output
    • request_defaults.rails.retrieval
    • request_defaults.rails.dialog
    • request_defaults.rails.tool_input
    • request_defaults.rails.tool_output
  • These are forwarded to the Guardrails server as remote request semantics. In this PR, retrieval and dialog are supported this way only: NeMo Relay does not currently expose separate managed retrieval or dialog execution surfaces to intercept locally.
  • The remote backend emits coarse backend-level marks:
    • nemo_guardrails.remote.start
    • nemo_guardrails.remote.end
    • nemo_guardrails.remote.error
  • These marks cover managed LLM remote execution and managed tool_output remote checks. They provide backend-level visibility into remote Guardrails activity without introducing separate NeMo Relay-native retrieval or dialog scopes in this slice.

Intentional PR2 boundary:

  • native remote support is openai_chat only
  • local backend is still not implemented
  • stock remote mode supports managed tool_output but not managed tool_input
  • this stays core-only; binding surface enablement is deferred

Validation:

  • cargo fmt --all
  • cargo test -p nemo-relay nemo_guardrails --lib --tests
  • cargo clippy --workspace --all-targets -- -D warnings
  • uv run pre-commit run --files crates/core/src/plugins/nemo_guardrails/component.rs crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs

Targeted live validation covered:

  • allowed and blocked non-streaming LLM requests
  • streaming requests
  • trusted HTTPS transport
  • managed tool_output blocked path
  • direct stock Guardrails repro confirming externally supplied pre-exec tool-call history does not activate remote managed tool_input

Notes:

  • uv run pre-commit run --all-files still reports an unrelated repo-environment failure in ty for unresolved deepagents integration imports
  • unrelated package-lock.json churn was restored and is not part of this PR

Where should the reviewer start?

Start in crates/core/src/plugins/nemo_guardrails/component.rs, then crates/core/src/plugins/nemo_guardrails/remote.rs.

The most important design decision in this PR is that the built-in plugin now implements a real remote execution backend while keeping the remote contract honest:

  • native remote support is OpenAI chat-completions shaped
  • LLM and managed tool_output execution are supported through the core runtime
  • stock remote managed tool_input is explicitly rejected instead of being left as a silent best-effort path
  • broader non-chat codec parity and the local Python runtime remain out of scope for this slice

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

  • Relates to #NMF-131
  • Relates to #NMF-148

@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented May 21, 2026

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

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR implements a remote backend for the NeMo Guardrails plugin, enabling routing of LLM and tool execution to a remote HTTP endpoint. It adds feature gating, extends request configuration with continuation fields (thread_id, state), implements non-streaming and SSE streaming execution paths with guardrails context injection, adds tool input/output remote checks with JSON rewriting, and provides comprehensive unit tests covering success and error paths.

Changes

Remote NeMo Guardrails Backend

Layer / File(s) Summary
Feature and dependency configuration
crates/core/Cargo.toml
New guardrails-remote feature gates reqwest and rustls and is included in default features.
Builtin plugin registration refactor
crates/core/src/plugin.rs
ensure_builtin_plugins_registered() refactored to use a local register_builtins closure passed into BUILTIN_PLUGIN_REGISTRATION.get_or_init().
Module exports and config schema
crates/core/src/plugins/nemo_guardrails/mod.rs, component.rs
Public submodule renamed to component; conditional remote module import with stub fallback; RequestDefaultsConfig extended with optional thread_id: Option<String> and state: Option<Json> fields; fields exposed in editor config and request-defaults validation.
Configuration dispatch and validation
crates/core/src/plugins/nemo_guardrails/component.rs
Plugin register() parses config and dispatches to register_nemo_guardrails_backend() by mode; new validate_remote_backend_support() enforces codec = openai_chat for remote mode with LLM surfaces enabled; validate_request_defaults() extended to validate thread_id min length (16 chars) and state structure (JSON object with only events/state keys).
Remote backend HTTP runtime and execution
crates/core/src/plugins/nemo_guardrails/remote.rs
RemoteBackendRuntime initializes reqwest client with rustls provider, timeout, and normalized headers; non-streaming execution POSTs to /v1/chat/completions, handles errors/responses, and emits telemetry marks; streaming execution validates HTTP success, spawns SSE decoder task forwarding chunks via bounded channel; tool input/output checks send remote prompts with tool-specific rail flags, reject on blocking rails, and rewrite tool arguments/result JSON; plugin wiring registers LLM/stream/tool intercepts with shared runtime; guardrails config builders inject context/thread/state and optional rails/llm/output/log settings; feature-disabled fallback returns RegistrationFailed.
Component test harness and schema validation
crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
TCP HTTP responder harness emulates remote endpoint; schema assertions updated for thread_id/state fields; plugin lifecycle tests refactored to assert automatic builtin registration; remote codec validation tests added; request-defaults validation tests updated for new field rules.
Remote backend execution and error handling tests
crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs
Tests for non-streaming and streaming success paths with mark validation; config_ids variant; HTTP error propagation (502/503); JSON parse failures; SSE malformed chunks; transport failures and preflight validation rejection.
Remote tool input/output rails and rewriting tests
crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs (continued)
Tests for tool input rejection on blocking rails, argument rewriting with JSON validation, output result rewriting, invalid/missing content errors, local callback failures, mismatched tool names, sequential input/output execution order, context forwarding to tool checks, and tool-only configuration isolation from LLM calls.

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title follows Conventional Commits format with correct type, lowercase scope implicit, imperative verb, and is under 72 characters.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description comprehensively covers implementation details, design rationale, and validation scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions github-actions Bot added size:XL PR is extra large Feature a new feature lang:rust PR changes/introduces Rust code size:XXL PR is very large and removed size:XL PR is extra large size:XXL PR is very large labels May 21, 2026
@afourniernv afourniernv marked this pull request as ready for review May 22, 2026 13:14
@afourniernv afourniernv requested a review from a team as a code owner May 22, 2026 13:14
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@crates/core/src/plugins/nemo_guardrails/component.rs`:
- Around line 956-968: The length check uses raw thread_id.len() while the
emptiness check uses thread_id.trim().is_empty(), causing inconsistent
validation; update the logic in component.rs around request_defaults.thread_id
(the block that calls push_policy_diag with policy.unsupported_value and
NEMO_GUARDRAILS_PLUGIN_KIND) to operate on a trimmed value (e.g., compute let
thread_id_trimmed = thread_id.trim() and use thread_id_trimmed.is_empty() and
thread_id_trimmed.len() or thread_id_trimmed.chars().count() for Unicode-aware
length) so whitespace padding is handled consistently (or alternatively add
explicit whitespace validation if padded IDs should be rejected).
- Around line 20-22: Gate the remote module import and usage behind a
feature/target cfg: change the unconditional mod remote/import of
register_remote_backend to something like #[cfg(feature = "remote")] #[path =
"remote.rs"] mod remote; and #[cfg(feature = "remote")] use
remote::register_remote_backend; then add a fallback stub for
register_remote_backend or inside register_nemo_guardrails_backend (e.g.,
#[cfg(not(feature = "remote"))] pub fn register_remote_backend(...) -> Result<_,
_> or have register_nemo_guardrails_backend return a clear Err when running on
unsupported targets like wasm32) so builds without the "remote" feature or on
wasm32 do not try to pull in reqwest; ensure the stub provides a clear
compile-time or runtime message about the missing feature/unsupported target.
🪄 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: 8eb2a87e-24a6-4818-b0bf-f4bcc6337f1e

📥 Commits

Reviewing files that changed from the base of the PR and between acafd6f and ca5c813.

📒 Files selected for processing (7)
  • crates/core/Cargo.toml
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/plugin_component_tests.rs
💤 Files with no reviewable changes (1)
  • crates/core/tests/unit/plugins/nemo_guardrails/plugin_component_tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (16)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use cargo fmt for Rust code formatting (rustfmt defaults)
Use cargo clippy -- -D warnings for Rust linting, treating all warnings as errors
Use Rust snake_case naming convention for Rust code
Run just test-rust for Rust test suite

Use snake_case naming convention for Rust identifiers (e.g., nemo_relay_tool_call)

**/*.rs: Any Rust change must run just test-rust
Any Rust change must run cargo fmt --all
Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all for all FFI work since it is Rust work
Run just test-rust to validate FFI changes
Run cargo clippy --workspace --all-targets -- -D warnings to enforce strict linting on FFI work

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

**/*.rs: Run cargo fmt --all when Rust files are changed as part of Node work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files are changed as part of Node work
Run just test-rust when Rust files are changed as part of Node work

**/*.rs: Run cargo fmt --all to format all Rust code
Run cargo clippy --workspace --all-targets -- -D warnings to enforce all clippy lints as errors

**/*.rs: Run cargo fmt --all when Rust files changed as part of WebAssembly work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files changed as part of WebAssembly work

**/*.rs: If any Rust code changed, always run just test-rust
If any Rust code changed, also run cargo fmt --all
If any Rust code changed, also run cargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting with cargo fmt --all
Run Rust linting with cargo clippy --workspace --all-targets -- -D warnings

Files:

  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.{rs,go,js,ts,jsx,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header with format: // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 in Rust, Go, JavaScript, and TypeScript files

Files:

  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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.toml and their actual usage across the codebase

Files:

  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/Cargo.toml
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/core or crates/adaptive must run the full language matrix

Files:

  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/Cargo.toml
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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:

  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/Cargo.toml
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/core or shared runtime semantics, also use validate-change for broader validation

crates/core/**/*.rs: Use Json = serde_json::Value in Rust-facing runtime APIs where the existing code expects JSON payloads.
Use Result<T> with FlowError in core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.

Files:

  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
crates/{core,adaptive}/**

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

If crates/core or crates/adaptive changed, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly

Files:

  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/Cargo.toml
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,bash,yml,yaml,toml,json,md,mjs,cjs}

📄 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/mod.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/Cargo.toml
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.{py,toml}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header with format: # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 in Python and TOML files

Files:

  • crates/core/Cargo.toml
**/Cargo.toml

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

Confirm or infer the target release version from upstream/main:Cargo.toml. Derive the release branch as release/<major>.<minor>.

Update WebAssembly crate names and generated package names during coordinated rename operations

Files:

  • crates/core/Cargo.toml
**/*.{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/Cargo.toml
{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:

  • crates/core/Cargo.toml
{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.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.rs
🔇 Additional comments (29)
crates/core/src/plugin.rs (1)

765-769: LGTM!

crates/core/src/plugins/nemo_guardrails/mod.rs (1)

14-14: LGTM!

crates/core/src/plugins/nemo_guardrails/component.rs (8)

189-194: LGTM!


320-321: LGTM!


362-372: LGTM!


434-447: LGTM!


527-528: LGTM!


902-926: LGTM!


969-992: LGTM!


1246-1247: LGTM!

crates/core/Cargo.toml (1)

17-22: ⚡ Quick win

No wasm32 build break: remote.rs already gates guardrails-remote deps

crates/core/src/plugins/nemo_guardrails/remote.rs only pulls in/uses reqwest and rustls under #[cfg(all(not(target_arch = "wasm32"), feature = "guardrails-remote"))], and it provides a wasm32 (and/or non-feature) register_remote_backend fallback under #[cfg(any(target_arch = "wasm32", not(feature = "guardrails-remote")))]. So crates/core/src/plugins/nemo_guardrails/component.rs can keep its unconditional mod remote; / use remote::register_remote_backend; without additional gating.

crates/core/src/plugins/nemo_guardrails/remote.rs (8)

1-57: LGTM!


59-99: LGTM!


101-221: LGTM!


223-403: LGTM!


405-452: LGTM!


454-520: LGTM!


530-715: LGTM!


718-941: LGTM!

crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs (10)

1-50: LGTM!


52-91: LGTM!


93-222: LGTM!


224-337: LGTM!


339-430: LGTM!


432-848: LGTM!


850-1171: LGTM!


1173-1683: LGTM!


1685-2209: LGTM!


2211-2465: LGTM!

Comment thread crates/core/src/plugins/nemo_guardrails/component.rs
Comment thread crates/core/src/plugins/nemo_guardrails/component.rs Outdated
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>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
@afourniernv afourniernv force-pushed the afournier/nmf-131-remote-backend branch from 8f2e3ae to 3c2276c Compare May 22, 2026 13:43
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

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/core/src/plugins/nemo_guardrails/component.rs`:
- Around line 985-999: The current validation for request_defaults.state only
ensures it contains 'events' or 'state' but doesn't reject extra keys; update
the check in the request_defaults.state handling so you validate that the
object's keys are a subset of the allowed set {'events','state'} and
push_policy_diag when any other key is present. Concretely, in the same block
that currently references request_defaults.state and calls push_policy_diag with
policy.unsupported_value, add logic to iterate the object's keys (or compute the
set difference) and if there are any keys besides "events" or "state" call
push_policy_diag(diagnostics, policy.unsupported_value,
"nemo_guardrails.unsupported_value",
Some(NEMO_GUARDRAILS_PLUGIN_KIND.to_string()),
Some("request_defaults.state".to_string()), "request_defaults.state must be
empty or contain only 'events' and/or 'state'".to_string()).

In `@crates/core/src/plugins/nemo_guardrails/remote.rs`:
- Around line 173-186: The code currently includes raw remote response bodies in
observability marks and error messages (seen where self.emit_mark calls pass
payload.clone() into remote_mark_data and where FlowError::Internal interpolates
the payload); instead, sanitize or omit the body before exporting by replacing
payload.clone() with a safe representation (e.g., None, a fixed string like
"<redacted>", or a truncated/hashed summary produced by a helper like
redact_payload(payload)) and ensure the FlowError message does not embed
sensitive contents (use status and a redacted summary instead); apply the same
change to the other occurrences mentioned (the remote_mark_data calls and
FlowError::Internal usages at the other locations).
- Around line 679-708: The code builds a rails map that always sets "tool_input"
and "tool_output" to false, causing tool-only checks to run under the wrong rail
family; update the rails construction in the RemoteCheckKind branch handling
(the rails variable created when matching RemoteCheckKind::Input/Output) to set
"tool_input" and "tool_output" according to the intended check type (e.g.,
enable tool_input for tool-input checks and tool_output for tool-output checks)
instead of hardcoding them false, then keep inserting rails into options and
preserving the existing request_defaults/log/guardrails insertion logic (see
symbols: RemoteCheckKind, rails, options, request_defaults, log, guardrails).

In `@crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs`:
- Around line 1-5: The PR lacks full Rust/core validation evidence — run the
required checks for changes under crates/core (including the unit tests in
tests/unit/plugins/nemo_guardrails/component_tests.rs): execute just test-rust,
cargo fmt --all, and cargo clippy --workspace --all-targets -- -D warnings, then
run the full language matrix for crates/core (all supported Rust toolchain
versions) and attach the resulting logs/screenshots to the PR; ensure the
artifacts explicitly reference the component_tests.rs run and note any fixes
made if formatting or clippy failures are found.
- Line 946: The test currently blocks on request_rx.recv().unwrap(), which can
hang; replace the blocking recv call with a bounded wait using
request_rx.recv_timeout(Duration::from_secs(...)) and handle the Err case to
fail the test with a clear timeout message (reference the request_rx and
captured variables). If the same test or helper also awaits stream.next().await
in a loop, wrap that await with tokio::time::timeout(Duration::from_secs(...),
stream.next()).await and convert the timeout result into a test failure message
so the test fails deterministically instead of hanging.
🪄 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: ffe36d84-5071-415c-a3a7-103f8e4b9fe0

📥 Commits

Reviewing files that changed from the base of the PR and between 8f2e3ae and 3c2276c.

📒 Files selected for processing (7)
  • crates/core/Cargo.toml
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/plugin_component_tests.rs
💤 Files with no reviewable changes (1)
  • crates/core/tests/unit/plugins/nemo_guardrails/plugin_component_tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (16)
**/*.{py,toml}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header with format: # SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 in Python and TOML files

Files:

  • crates/core/Cargo.toml
**/{Cargo.toml,**/*.rs}

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

Maintain consistency between Rust package names in Cargo.toml and their actual usage across the codebase

Files:

  • crates/core/Cargo.toml
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/Cargo.toml

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

Confirm or infer the target release version from upstream/main:Cargo.toml. Derive the release branch as release/<major>.<minor>.

Update WebAssembly crate names and generated package names during coordinated rename operations

Files:

  • crates/core/Cargo.toml
{crates/core,crates/adaptive}/**/*

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

Changes to crates/core or crates/adaptive must run the full language matrix

Files:

  • crates/core/Cargo.toml
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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:

  • crates/core/Cargo.toml
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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:

  • crates/core/Cargo.toml
crates/{core,adaptive}/**

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

If crates/core or crates/adaptive changed, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly

Files:

  • crates/core/Cargo.toml
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
{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:

  • crates/core/Cargo.toml
**/*.{rs,py,js,ts,tsx,jsx,go,sh,bash,yml,yaml,toml,json,md,mjs,cjs}

📄 CodeRabbit inference engine (AGENTS.md)

Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.

Files:

  • crates/core/Cargo.toml
  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use cargo fmt for Rust code formatting (rustfmt defaults)
Use cargo clippy -- -D warnings for Rust linting, treating all warnings as errors
Use Rust snake_case naming convention for Rust code
Run just test-rust for Rust test suite

Use snake_case naming convention for Rust identifiers (e.g., nemo_relay_tool_call)

**/*.rs: Any Rust change must run just test-rust
Any Rust change must run cargo fmt --all
Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all for all FFI work since it is Rust work
Run just test-rust to validate FFI changes
Run cargo clippy --workspace --all-targets -- -D warnings to enforce strict linting on FFI work

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

**/*.rs: Run cargo fmt --all when Rust files are changed as part of Node work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files are changed as part of Node work
Run just test-rust when Rust files are changed as part of Node work

**/*.rs: Run cargo fmt --all to format all Rust code
Run cargo clippy --workspace --all-targets -- -D warnings to enforce all clippy lints as errors

**/*.rs: Run cargo fmt --all when Rust files changed as part of WebAssembly work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files changed as part of WebAssembly work

**/*.rs: If any Rust code changed, always run just test-rust
If any Rust code changed, also run cargo fmt --all
If any Rust code changed, also run cargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting with cargo fmt --all
Run Rust linting with cargo clippy --workspace --all-targets -- -D warnings

Files:

  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.{rs,go,js,ts,jsx,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header with format: // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 in Rust, Go, JavaScript, and TypeScript files

Files:

  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/core or shared runtime semantics, also use validate-change for broader validation

crates/core/**/*.rs: Use Json = serde_json::Value in Rust-facing runtime APIs where the existing code expects JSON payloads.
Use Result<T> with FlowError in core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.

Files:

  • crates/core/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/src/plugin.rs
  • crates/core/src/plugins/nemo_guardrails/mod.rs
  • crates/core/src/plugins/nemo_guardrails/component.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/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/plugins/nemo_guardrails/component_tests.rs
🔇 Additional comments (2)
crates/core/Cargo.toml (1)

17-22: Run the required validation matrix before merging.

The PR notes only mention cargo test -p nemo-flow nemo_guardrails --lib --tests, but this change set touches crates/core Rust code and crate features. Please verify the required Rust checks (just test-rust, cargo fmt --all, cargo clippy --workspace --all-targets -- -D warnings) and the broader crates/core validation (validate-change plus the full Rust/Python/Go/Node.js/WebAssembly matrix) were run on this branch.

As per coding guidelines, "**/*.rs: Any Rust change must run just test-rust", "Any Rust change must run cargo fmt --all", "`Any Rust change must run `cargo clippy --workspace --all-targets -- -D warnings", "crates/core/**/*.rs: If the change touched crates/core or shared runtime semantics, also use validate-change for broader validation", and "crates/{core,adaptive}/**: If crates/coreorcrates/adaptive changed, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly."

crates/core/src/plugin.rs (1)

765-768: Guard nemo_guardrails built-in registration when guardrails-remote is off.
In crates/core/src/plugin.rs (lines 765-768), register_builtins unconditionally calls crate::plugins::nemo_guardrails::component::register_nemo_guardrails_component(). If that component (or its dependencies like reqwest/rustls) is gated behind guardrails-remote without a no-op/stub for the disabled case, this will break compilation. Ensure there’s either a stub/no-op implementation when the feature is off, or wrap the call (or provide a feature-gated alternative) to keep built-in initialization feature-compatible.

Comment thread crates/core/src/plugins/nemo_guardrails/component.rs Outdated
Comment thread crates/core/src/plugins/nemo_guardrails/remote.rs Outdated
Comment thread crates/core/src/plugins/nemo_guardrails/remote.rs Outdated
Comment thread crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
Comment thread crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs Outdated
Signed-off-by: Alex Fournier <afournier@nvidia.com>
@afourniernv
Copy link
Copy Markdown
Contributor Author

@willkill07 @dagardner-nv live tested + no cargo blast radius. Did have to add some minimal deps. ready for review.

Copy link
Copy Markdown
Member

@willkill07 willkill07 left a comment

Choose a reason for hiding this comment

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

First brief pass. I'll have a more complete pass later.

Comment thread crates/core/src/plugins/nemo_guardrails/remote.rs Outdated
Comment thread crates/core/src/plugins/nemo_guardrails/component.rs
Comment thread crates/core/src/plugins/nemo_guardrails/remote.rs Outdated
Comment thread crates/core/src/plugins/nemo_guardrails/remote.rs Outdated
Comment thread crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
@willkill07 willkill07 added this to the 0.3 milestone May 22, 2026
@willkill07
Copy link
Copy Markdown
Member

/ok to test 60999ac

Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
crates/core/src/plugins/nemo_guardrails/remote.rs (1)

183-197: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Stop returning raw remote error bodies in FlowError.

The marks are redacted now, but these error paths still interpolate the full remote body into FlowError::Internal. That can surface prompts, tool payloads, or backend diagnostics to callers and logs. Return a redacted/truncated summary here too, and update the HTTP error assertions in crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs to match.

Also applies to: 291-321, 573-588

🤖 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/remote.rs` around lines 183 - 197,
The FlowError::Internal for non-success HTTP responses currently interpolates
the full remote response body (e.g., the error case inside the non-success
branch where self.emit_mark(...) is called), so change those error returns to
include only a redacted or truncated summary instead of the raw payload: call
redact_remote_error_payload(status.as_u16(), &payload) (or use the same
redaction helper used for marks) and include only the status and that
redacted/truncated string in the FlowError::Internal message; apply the same
change to the other non-success branches mentioned (around the other ranges in
this file) and update the corresponding assertions in
crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs to expect the
redacted/truncated summary rather than the full body.
🤖 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/remote.rs`:
- Around line 87-91: The outbound llm_guardrails config currently only uses
request_defaults so top-level surface flags are ignored; modify the call to
build_llm_guardrails_config (where llm_guardrails is constructed for the remote,
using remote.config_id/remote.config_ids) to accept the top-level booleans for
input/output and, inside that builder or immediately after, set
guardrails.options.rails families to false for any disabled top-level surface
(force input rails false if input=false, force output rails false if
output=false) so the remote receives explicit disables; also add regression
tests for input-only and output-only flows to verify the disabled family
behavior remains backward-compatible and document no behavioral change unless
tests indicate migration.
- Around line 894-929: The function build_tool_check_guardrails_config currently
hardcodes "tool_input": true or "tool_output": true and thus discards any
selector configured in request_defaults; update it to merge the configured
selector instead of overwriting it: read the optional configured rails object
from request_defaults (via request_defaults -> log -> "rails"), clone it, and
when creating the synthesized rails Json use the configured value for the
relevant key ("tool_input" or "tool_output") if present (preserve whatever Json
selector is stored), otherwise default to Json::Bool(true); keep the other rail
families set to false and insert the merged rails into options as before
(reference function name build_tool_check_guardrails_config and the
"rails"/"log" keys).

---

Duplicate comments:
In `@crates/core/src/plugins/nemo_guardrails/remote.rs`:
- Around line 183-197: The FlowError::Internal for non-success HTTP responses
currently interpolates the full remote response body (e.g., the error case
inside the non-success branch where self.emit_mark(...) is called), so change
those error returns to include only a redacted or truncated summary instead of
the raw payload: call redact_remote_error_payload(status.as_u16(), &payload) (or
use the same redaction helper used for marks) and include only the status and
that redacted/truncated string in the FlowError::Internal message; apply the
same change to the other non-success branches mentioned (around the other ranges
in this file) and update the corresponding assertions in
crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs to expect the
redacted/truncated summary rather than the full body.
🪄 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: 57ed3831-20c6-4ff7-beb3-261e5b5cda9f

📥 Commits

Reviewing files that changed from the base of the PR and between 60999ac and fa9e2bc.

📒 Files selected for processing (3)
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (12)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use cargo fmt for Rust code formatting (rustfmt defaults)
Use cargo clippy -- -D warnings for Rust linting, treating all warnings as errors
Use Rust snake_case naming convention for Rust code
Run just test-rust for Rust test suite

Use snake_case naming convention for Rust identifiers (e.g., nemo_relay_tool_call)

**/*.rs: Any Rust change must run just test-rust
Any Rust change must run cargo fmt --all
Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all for all FFI work since it is Rust work
Run just test-rust to validate FFI changes
Run cargo clippy --workspace --all-targets -- -D warnings to enforce strict linting on FFI work

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

**/*.rs: Run cargo fmt --all when Rust files are changed as part of Node work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files are changed as part of Node work
Run just test-rust when Rust files are changed as part of Node work

**/*.rs: Run cargo fmt --all to format all Rust code
Run cargo clippy --workspace --all-targets -- -D warnings to enforce all clippy lints as errors

**/*.rs: Run cargo fmt --all when Rust files changed as part of WebAssembly work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files changed as part of WebAssembly work

**/*.rs: If any Rust code changed, always run just test-rust
If any Rust code changed, also run cargo fmt --all
If any Rust code changed, also run cargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting with cargo fmt --all
Run Rust linting with cargo clippy --workspace --all-targets -- -D warnings

Files:

  • crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.{rs,go,js,ts,jsx,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header with format: // SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 in Rust, Go, JavaScript, and TypeScript files

Files:

  • crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/plugins/nemo_guardrails/remote_tests.rs
  • crates/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.toml and their actual usage across the codebase

Files:

  • crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/plugins/nemo_guardrails/remote_tests.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/core or crates/adaptive must run the full language matrix

Files:

  • crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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:

  • crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/core or shared runtime semantics, also use validate-change for broader validation

crates/core/**/*.rs: Use Json = serde_json::Value in Rust-facing runtime APIs where the existing code expects JSON payloads.
Use Result<T> with FlowError in core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.

Files:

  • crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
crates/{core,adaptive}/**

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

If crates/core or crates/adaptive changed, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly

Files:

  • crates/core/tests/unit/plugins/nemo_guardrails/remote_tests.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,bash,yml,yaml,toml,json,md,mjs,cjs}

📄 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/remote_tests.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/plugins/nemo_guardrails/remote_tests.rs
  • crates/core/src/plugins/nemo_guardrails/remote.rs
  • crates/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/plugins/nemo_guardrails/remote_tests.rs
  • crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs
🔇 Additional comments (1)
crates/core/tests/unit/plugins/nemo_guardrails/component_tests.rs (1)

859-860: LGTM!

Comment thread crates/core/src/plugins/nemo_guardrails/remote.rs
Comment thread crates/core/src/plugins/nemo_guardrails/remote.rs
Signed-off-by: Alex Fournier <afournier@nvidia.com>
@willkill07
Copy link
Copy Markdown
Member

/ok to test 38aa2e3

Comment thread crates/core/src/plugin.rs
{
let register_builtins = || {
crate::observability::plugin_component::register_observability_component()?;
crate::plugins::nemo_guardrails::component::register_nemo_guardrails_component()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't this be guarded on !wasm ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think “known but unavailable” is the better behavior.

but If you specifically want builtin registration to mean “fully usable on this target,” then yes, we should gate it.

})
}

async fn execute(&self, request: LlmRequest, stream: bool) -> crate::error::Result<Json> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

cognitive complexity of this function is really high -- can we factor out common logic? (same with execute_stream)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

I factored the common request/response plumbing out of execute / execute_stream, and also pulled the spawned SSE decode loop into a helper so the top-level methods read more as orchestration than transport detail.

Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature a new feature lang:rust PR changes/introduces Rust code size:XL PR is extra large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants