feat(sanitizers)!: add mark and scope event sanitizer registries [1/6]#371
Conversation
Signed-off-by: Will Killian <wkillian@nvidia.com>
License DiffCompared against Lockfile license changesLockfile License ChangesRustAdded
Removed
Updated/Changed
NodeAdded
Removed
Updated/Changed
PythonAdded
Removed
Updated/Changed
Status output |
WalkthroughAdds event field sanitization types and callbacks, applies sanitization before emitting lifecycle events, wires new guardrail registries and plugin APIs, extends native and worker plugin support, and updates proto values plus test coverage. ChangesEvent Sanitization Feature
Estimated code review effort: 4 (Complex) | ~75 minutes Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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/api/shared.rs`:
- Around line 44-93: The sanitizer path in sanitize_event_with_scope_stack
currently fails open by returning the original Event when
global_context().read() errors, which can leak unsanitized data. Update
sanitize_event_with_scope_stack (and its sanitize_event caller if needed) to
fail closed by dropping the event or surfacing an error instead of returning the
raw event on lock/read failure, matching the existing stream wrapper behavior.
Keep the existing event type handling for Event::Mark, Event::Scope Start, and
other Scope events, but ensure any context read failure prevents emission of the
unsanitized payload.
In `@crates/plugin/tests/typed_callbacks.rs`:
- Around line 2627-2657: The new ABI callback coverage in the typed_callbacks
test only checks null user_data and out_fields_json, so add direct null-pointer
assertions for the required input strings as well. Update the test around the
event sanitize registration callback to invoke the registered cb with a null
event_json and separately with a null fields_json, and assert
NemoRelayStatus::NullPointer in each case to cover the contract of the new
callback surface.
- Around line 3038-3050: The invalid-fields assertion in the typed callback test
is not verifying that the trampoline clears a previously set output pointer
because `out` is already null after the invalid-event case. In
`typed_callbacks.rs`, reset `out` to `stale_out` before calling
`registration.cb` with `invalid_fields`, then keep asserting
`NemoRelayStatus::InvalidJson` and that `out` becomes null so the test covers
clearing stale output on error.
In `@crates/types/src/api/event.rs`:
- Around line 367-384: The sanitization flow is replacing the entire
CategoryProfile instead of preserving existing fields, so update
apply_sanitize_fields() and its use of EventSanitizeFields::category_profile to
merge only the sanitizer-provided fields into the current profile. Keep
tool_call_id and extra intact when a sanitizer changes only subtype or
model_name, and only fall back to full replacement if that is the intended
contract for EventSanitizeFields and its docs.
🪄 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: b57882e6-204b-47d9-b83e-5d6da43f7ecb
📒 Files selected for processing (29)
crates/core/src/api/llm.rscrates/core/src/api/registry.rscrates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/api/runtime/state.rscrates/core/src/api/scope.rscrates/core/src/api/shared.rscrates/core/src/api/tool.rscrates/core/src/context/registries.rscrates/core/src/plugin.rscrates/core/src/plugin/dynamic/native.rscrates/core/src/plugin/dynamic/worker.rscrates/core/src/stream.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/integration/api_surface_tests.rscrates/core/tests/integration/middleware_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/unit/types_tests.rscrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rscrates/types/src/api/event.rscrates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.protocrates/worker-proto/tests/proto_tests.rscrates/worker/src/lib.rscrates/worker/tests/worker_sdk_tests.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: Check / Run
- GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (19)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
**/*.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 workFollow Rust naming conventions, including
snake_caseidentifiers and Rust-facing runtime API shapes.
**/*.rs: When changing the core runtime or Rust-facing API surface, format Rust code withcargo fmt(rustfmt defaults), keepcargo clippy -- -D warningsclean, and passcargo deny check.
When touching the core Rust crate, run the Rust tests and the other affected binding test suites because the bindings depend on the core runtime.
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/worker-proto/tests/proto_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/types/src/api/event.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/src/lib.rscrates/core/tests/integration/api_surface_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.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/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/tests/integration/api_surface_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 validationIf the change touched shared runtime semantics in
crates/core, also usevalidate-change.
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/tests/integration/api_surface_tests.rs
**/*.{rs,py,js,ts,mjs,c,h,md,toml,yml,yaml,sh,json,go}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source files, documentation, scripts, and configuration files.
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/worker-proto/tests/proto_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/types/src/api/event.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/src/lib.rscrates/core/tests/integration/api_surface_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
crates/{core,adaptive,ffi,python,node,wasm}/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Use
Json = serde_json::Valuein Rust-facing runtime APIs where existing code expects JSON payloads.
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/tests/integration/api_surface_tests.rs
crates/{core,adaptive}/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Use
Result<T>withFlowErrorin core runtime paths, and keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/tests/integration/api_surface_tests.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/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/tests/integration/api_surface_tests.rs
**/*.{rs,py,go,js,ts,jsx,tsx,md,mdx,toml,yaml,yml,html}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
All source files must include an SPDX license header using the comment syntax appropriate for the file type, with SPDX-FileCopyrightText for 2026 NVIDIA CORPORATION & AFFILIATES and SPDX-License-Identifier: Apache-2.0.
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/worker-proto/tests/proto_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/types/src/api/event.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/src/lib.rscrates/core/tests/integration/api_surface_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Use the naming conventions appropriate to each language: Rust
snake_case, C FFI exports prefixednemo_relay_, GoPascalCase, Node.jscamelCase, and Pythonsnake_case.
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/worker-proto/tests/proto_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/types/src/api/event.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/src/lib.rscrates/core/tests/integration/api_surface_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts,md,mdx,toml,yaml,yml,json}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Avoid using
SONAR_IGNORE_START/SONAR_IGNORE_ENDexcept for documented false positives; keep the ignored block small, add a brief explanatory comment, and call it out in the PR description.
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/worker-proto/tests/proto_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/types/src/api/event.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/src/lib.rscrates/core/tests/integration/api_surface_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
crates/core/src/api/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Implement public runtime behavior first in
crates/core/src/api/and related core modules such ascrates/core/src/api/runtime/,crates/core/src/codec/, orcrates/core/src/json.rs.
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/core/src/api/registry.rs
**/*.{rs,py,go,js,ts,wasm}
📄 CodeRabbit inference engine (.agents/skills/maintain-observability/SKILL.md)
Ensure binding-native wrappers expose the same observability configuration knobs and lifecycle behavior across Rust, Python, Go, Node.js, and WebAssembly.
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/worker-proto/tests/proto_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/types/src/api/event.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/src/lib.rscrates/core/tests/integration/api_surface_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
**/*.{rs,rlib}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*.{rs,rlib}: 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.
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/worker-proto/tests/proto_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/types/src/api/event.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/src/lib.rscrates/core/tests/integration/api_surface_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
crates/core/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/corechanged, run the full validation matrix across Rust, Python, Go, Node.js, and WebAssembly.
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/tests/integration/api_surface_tests.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 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, integrations, 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 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 skills/ # Published Codex/agent skills for NeMo Relay usage patternsPrerequisites
Insta...
Files:
crates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/stream.rscrates/worker-proto/tests/proto_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.protocrates/core/tests/integration/native_plugin_tests.rscrates/core/src/context/registries.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/scope.rscrates/core/src/api/tool.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/core/src/api/llm.rscrates/types/src/api/event.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/registry.rscrates/core/src/plugin.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/src/lib.rscrates/core/tests/integration/api_surface_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
crates/core/src/api/runtime/callbacks.rs
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Define or reuse callback type aliases in
crates/core/src/api/runtime/callbacks.rsusingBox<dyn Fn(...)>pattern for new middleware types
Files:
crates/core/src/api/runtime/callbacks.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/worker-proto/tests/proto_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/types_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/tests/integration/middleware_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/tests/integration/api_surface_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/plugin/tests/typed_callbacks.rs
crates/core/src/api/{tool,llm}.rs
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Wire the new middleware chain into the execute path in
crates/core/src/api/tool.rsorcrates/core/src/api/llm.rsat the appropriate pipeline stage
Files:
crates/core/src/api/tool.rscrates/core/src/api/llm.rs
crates/core/src/api/runtime/state.rs
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
crates/core/src/api/runtime/state.rs: Add registry fields asSortedRegistry<GuardrailEntry<T>>orSortedRegistry<Intercept<T>>toNemoRelayContextStateincrates/core/src/api/runtime/state.rs
Add chain execution helpers toNemoRelayContextStatefollowing the pattern of existing methods liketool_sanitize_request_chainortool_request_intercepts_chain
Files:
crates/core/src/api/runtime/state.rs
crates/core/src/api/registry.rs
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Use existing
global_*_registry_api!andscope_*_registry_api!macro patterns incrates/core/src/api/registry.rsfor both global and scope-local registration APIs unless design explicitly rules one out
Files:
crates/core/src/api/registry.rs
🪛 Buf (1.71.0)
crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto
[error] 49-49: Enum value name "MARK_SANITIZE_GUARDRAIL" should be prefixed with "REGISTRATION_SURFACE_".
(ENUM_VALUE_PREFIX)
[error] 50-50: Enum value name "SCOPE_SANITIZE_START_GUARDRAIL" should be prefixed with "REGISTRATION_SURFACE_".
(ENUM_VALUE_PREFIX)
[error] 51-51: Enum value name "SCOPE_SANITIZE_END_GUARDRAIL" should be prefixed with "REGISTRATION_SURFACE_".
(ENUM_VALUE_PREFIX)
🔇 Additional comments (30)
crates/types/src/api/event.rs (1)
706-712: LGTM!crates/core/src/api/runtime/callbacks.rs (1)
17-30: LGTM!crates/core/src/api/shared.rs (1)
8-11: LGTM!crates/core/src/api/scope.rs (1)
10-12: LGTM!Also applies to: 234-238, 262-298, 324-352
crates/core/src/api/tool.rs (1)
14-14: LGTM!Also applies to: 255-258, 339-365, 367-383
crates/core/src/api/runtime/state.rs (1)
24-31: LGTM!Also applies to: 53-58, 96-98, 557-587, 589-634
crates/core/src/api/runtime.rs (1)
13-14: LGTM!crates/core/tests/unit/types_tests.rs (1)
13-15: LGTM!Also applies to: 951-992
crates/core/src/api/llm.rs (1)
24-25: LGTM!Also applies to: 324-324, 351-351, 525-525, 557-557
crates/core/src/stream.rs (1)
40-40: LGTM!Also applies to: 231-231, 259-259
crates/core/src/context/registries.rs (1)
14-14: LGTM!Also applies to: 27-32, 68-70
crates/core/src/api/registry.rs (1)
8-8: LGTM! Macro invocations correctly wire the three new guardrail surfaces to the fields added inregistries.rs, consistent with the establishedglobal_guardrail_registry_api!/scope_guardrail_registry_api!pattern.Also applies to: 470-494, 607-631
crates/core/tests/integration/api_surface_tests.rs (1)
13-13: LGTM! Priority ordering, scope-local inheritance to nested scopes, duplicate/missing-scope error paths, and cleanup are all exercised correctly and consistently with the sanitizer contract.Also applies to: 23-47, 80-141, 143-281, 565-587, 745-794, 949-978, 1048-1071, 1103-1103, 1112-1116, 1380-1389, 1447-1447, 1463-1463
crates/core/src/plugin.rs (1)
26-39: LGTM! New sanitizer registration methods mirror the establishedPluginRegistrationContextpattern (qualify → register → push rollback closure), and error message prefixes match the corresponding test expectations inplugin_tests.rs.Also applies to: 326-408
crates/core/tests/integration/middleware_tests.rs (1)
29-35: LGTM! Sanitizer mutation logic (merge vs. full replace) is consistent with the pre-existing metadata state in each test, and assertions/cleanup correctly reflect that.Also applies to: 674-684, 774-775, 803-803, 3122-3130, 3218-3228
crates/core/tests/unit/plugin_tests.rs (1)
986-999: LGTM! New sanitizer coverage is correctly ordered against theexpected_messageszip and matches the error-prefix strings defined inplugin.rs.Also applies to: 1074-1091, 1281-1294, 1368-1370
crates/plugin/src/lib.rs (1)
20-20: LGTM!Also applies to: 203-210, 506-535, 1284-1374, 1701-1763, 2097-2124
crates/core/src/plugin/dynamic/native.rs (1)
18-40: LGTM!Also applies to: 600-605, 1410-1455, 1475-1530
crates/core/tests/integration/native_plugin_tests.rs (1)
165-196: LGTM!Also applies to: 218-221, 231-234, 250-250
crates/plugin/tests/typed_callbacks.rs (1)
17-21: LGTM!Also applies to: 41-56, 229-229, 286-286, 316-436, 589-597, 1082-1110, 1155-1182, 1373-1380, 2127-2201, 2232-2309, 3008-3037, 3051-3059, 4856-4919
crates/worker/tests/worker_sdk_tests.rs (1)
201-201: LGTM!Also applies to: 457-481, 1003-1023, 1136-1146, 1563-1574, 2176-2192
crates/core/tests/integration/worker_plugin_tests.rs (1)
105-136: LGTM!Also applies to: 164-167, 177-184, 231-231
crates/core/tests/unit/dynamic_worker_tests.rs (1)
379-379: LGTM!Also applies to: 439-451
crates/worker/src/lib.rs (2)
142-156: 🎯 Functional Correctness | ⚡ Quick winShared
event_sanitizersmap can misroute callbacks across surfaces.
event_sanitizers: HashMap<String, EventSanitizeFn>is shared byMarkSanitizeGuardrail,ScopeSanitizeStartGuardrail, andScopeSanitizeEndGuardrail, keyed only byname. Every other guardrail family here (tool/llm sanitize request vs. response, etc.) uses a dedicated map per surface, so a name is only ever ambiguous within one surface. If a plugin registers the samenameon two of these three sanitize surfaces, the second registration silently overwrites the first in this map, andevent_sanitizer()(lines 1523-1533) has no way to disambiguate by surface — the wrong sanitizer runs for mark vs. scope-start/end events.This was raised in a prior review round and dismissed as "consistent with other middleware," but the other middleware maps are actually per-surface, not shared — worth revisiting.
🛠️ Proposed fix using per-surface maps (or a compound key)
struct WorkerHandlers { registrations: Vec<Registration>, subscribers: HashMap<String, SubscriberFn>, - event_sanitizers: HashMap<String, EventSanitizeFn>, + mark_sanitizers: HashMap<String, EventSanitizeFn>, + scope_start_sanitizers: HashMap<String, EventSanitizeFn>, + scope_end_sanitizers: HashMap<String, EventSanitizeFn>, ... }Then route inserts/lookups in
register_event_sanitizerandevent_sanitizerbysurfaceinto the matching map instead of a single shared one.Also applies to: 198-211, 1523-1533
37-37: LGTM!Also applies to: 121-122, 1402-1413, 1997-2014
crates/core/tests/fixtures/native_plugin/src/lib.rs (1)
8-9: LGTM!Also applies to: 50-62, 194-200
crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto (1)
49-51: 📐 Maintainability & Code QualityBuf flags missing enum-value prefix; matches existing convention.
Static analysis flags
MARK_SANITIZE_GUARDRAIL,SCOPE_SANITIZE_START_GUARDRAIL, andSCOPE_SANITIZE_END_GUARDRAILfor lacking theREGISTRATION_SURFACE_prefix, but all 12 pre-existing values in this enum (e.g.,SUBSCRIBER,TOOL_SANITIZE_REQUEST_GUARDRAIL) have the same "violation," so this isn't a new regression. Worth confirming whetherENUM_VALUE_PREFIXis intentionally disabled/excepted in the project's buf lint config, since otherwise CI would already be failing on the pre-existing entries.Source: Linters/SAST tools
crates/worker-proto/tests/proto_tests.rs (1)
41-43: LGTM!crates/core/tests/fixtures/worker_plugin/src/main.rs (1)
9-9: LGTM!Also applies to: 64-76, 97-103
crates/core/src/plugin/dynamic/worker.rs (1)
54-54: LGTM!Also applies to: 815-837, 1169-1188
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/core/src/api/shared.rs (1)
45-94: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winFail-closed fix confirmed; consider logging the drop path.
The
Err(_) => return Nonefix for the previously-flagged fail-open issue is in place and correct. One gap: once this path triggers (context lock poisoned), every subsequent mark/scope event is silently dropped with no diagnostic signal — in an observability runtime, losing events silently is worth atracing::warn!(or equivalent) so operators can detect degraded sanitization rather than just missing data downstream.♻️ Suggested addition
let state = match context.read() { Ok(state) => state, - Err(_) => return None, + Err(_) => { + tracing::warn!("dropping event: sanitizer context lock poisoned"); + return None; + } };🤖 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/api/shared.rs` around lines 45 - 94, In sanitize_event_with_scope_stack, the fail-closed return on a poisoned global_context read is correct, but the drop path is silent. Add a diagnostic log (for example via tracing::warn!) immediately before returning None in the Err(_) branch so operators can detect when mark/scope events are being discarded due to sanitization state failure. Keep the change localized to sanitize_event_with_scope_stack and preserve the existing None behavior.
🤖 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/worker/src/lib.rs`:
- Around line 1314-1325: The duplicate-registration error in
validate_unique_registrations currently formats registration.surface as a raw
integer, which makes the WorkerSdkError hard to read. Update the error निर्माण
in validate_unique_registrations to render a human-friendly surface name instead
of the protobuf i32, using the appropriate surface enum/display helper already
available in this module or nearby types. Keep the duplicate local_name wording,
but ensure the surface value in the formatted message is descriptive for logs
and gRPC errors.
---
Outside diff comments:
In `@crates/core/src/api/shared.rs`:
- Around line 45-94: In sanitize_event_with_scope_stack, the fail-closed return
on a poisoned global_context read is correct, but the drop path is silent. Add a
diagnostic log (for example via tracing::warn!) immediately before returning
None in the Err(_) branch so operators can detect when mark/scope events are
being discarded due to sanitization state failure. Keep the change localized to
sanitize_event_with_scope_stack and preserve the existing None behavior.
🪄 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: b116f01b-b5ce-4bec-86ba-0a654baffc6e
📒 Files selected for processing (11)
crates/core/src/api/llm.rscrates/core/src/api/runtime/state.rscrates/core/src/api/scope.rscrates/core/src/api/shared.rscrates/core/src/api/tool.rscrates/core/src/stream.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/integration/worker_plugin_tests.rscrates/plugin/tests/typed_callbacks.rscrates/worker/src/lib.rscrates/worker/tests/worker_sdk_tests.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: Check / Run
- GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (17)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
**/*.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 workFollow Rust naming conventions, including
snake_caseidentifiers and Rust-facing runtime API shapes.
**/*.rs: When changing the core runtime or Rust-facing API surface, format Rust code withcargo fmt(rustfmt defaults), keepcargo clippy -- -D warningsclean, and passcargo deny check.
When touching the core Rust crate, run the Rust tests and the other affected binding test suites because the bindings depend on the core runtime.
Files:
crates/core/src/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/worker/tests/worker_sdk_tests.rscrates/worker/src/lib.rscrates/plugin/tests/typed_callbacks.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/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.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 validationIf the change touched shared runtime semantics in
crates/core, also usevalidate-change.
Files:
crates/core/src/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rs
**/*.{rs,py,js,ts,mjs,c,h,md,toml,yml,yaml,sh,json,go}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source files, documentation, scripts, and configuration files.
Files:
crates/core/src/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/worker/tests/worker_sdk_tests.rscrates/worker/src/lib.rscrates/plugin/tests/typed_callbacks.rs
crates/{core,adaptive,ffi,python,node,wasm}/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Use
Json = serde_json::Valuein Rust-facing runtime APIs where existing code expects JSON payloads.
Files:
crates/core/src/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rs
crates/{core,adaptive}/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
Use
Result<T>withFlowErrorin core runtime paths, and keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/src/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.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/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rs
**/*.{rs,py,go,js,ts,jsx,tsx,md,mdx,toml,yaml,yml,html}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
All source files must include an SPDX license header using the comment syntax appropriate for the file type, with SPDX-FileCopyrightText for 2026 NVIDIA CORPORATION & AFFILIATES and SPDX-License-Identifier: Apache-2.0.
Files:
crates/core/src/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/worker/tests/worker_sdk_tests.rscrates/worker/src/lib.rscrates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Use the naming conventions appropriate to each language: Rust
snake_case, C FFI exports prefixednemo_relay_, GoPascalCase, Node.jscamelCase, and Pythonsnake_case.
Files:
crates/core/src/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/worker/tests/worker_sdk_tests.rscrates/worker/src/lib.rscrates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts,md,mdx,toml,yaml,yml,json}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Avoid using
SONAR_IGNORE_START/SONAR_IGNORE_ENDexcept for documented false positives; keep the ignored block small, add a brief explanatory comment, and call it out in the PR description.
Files:
crates/core/src/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/worker/tests/worker_sdk_tests.rscrates/worker/src/lib.rscrates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts,wasm}
📄 CodeRabbit inference engine (.agents/skills/maintain-observability/SKILL.md)
Ensure binding-native wrappers expose the same observability configuration knobs and lifecycle behavior across Rust, Python, Go, Node.js, and WebAssembly.
Files:
crates/core/src/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/worker/tests/worker_sdk_tests.rscrates/worker/src/lib.rscrates/plugin/tests/typed_callbacks.rs
**/*.{rs,rlib}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*.{rs,rlib}: 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.
Files:
crates/core/src/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/worker/tests/worker_sdk_tests.rscrates/worker/src/lib.rscrates/plugin/tests/typed_callbacks.rs
crates/core/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/corechanged, run the full validation matrix across Rust, Python, Go, Node.js, and WebAssembly.
Files:
crates/core/src/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.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 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, integrations, 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 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 skills/ # Published Codex/agent skills for NeMo Relay usage patternsPrerequisites
Insta...
Files:
crates/core/src/stream.rscrates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/src/api/scope.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.rscrates/worker/tests/worker_sdk_tests.rscrates/worker/src/lib.rscrates/plugin/tests/typed_callbacks.rs
crates/core/src/api/{tool,llm}.rs
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Wire the new middleware chain into the execute path in
crates/core/src/api/tool.rsorcrates/core/src/api/llm.rsat the appropriate pipeline stage
Files:
crates/core/src/api/llm.rscrates/core/src/api/tool.rs
crates/core/src/api/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Implement public runtime behavior first in
crates/core/src/api/and related core modules such ascrates/core/src/api/runtime/,crates/core/src/codec/, orcrates/core/src/json.rs.
Files:
crates/core/src/api/llm.rscrates/core/src/api/tool.rscrates/core/src/api/scope.rscrates/core/src/api/shared.rscrates/core/src/api/runtime/state.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/fixtures/worker_plugin/src/main.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/plugin/tests/typed_callbacks.rs
crates/core/src/api/runtime/state.rs
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
crates/core/src/api/runtime/state.rs: Add registry fields asSortedRegistry<GuardrailEntry<T>>orSortedRegistry<Intercept<T>>toNemoRelayContextStateincrates/core/src/api/runtime/state.rs
Add chain execution helpers toNemoRelayContextStatefollowing the pattern of existing methods liketool_sanitize_request_chainortool_request_intercepts_chain
Files:
crates/core/src/api/runtime/state.rs
🔇 Additional comments (14)
crates/plugin/tests/typed_callbacks.rs (1)
2647-2668: LGTM! Both previously-requested fixes — null-pointer coverage forevent/fields, and theout = stale_outreset before the invalid-fields case — are present and correct.Also applies to: 3060-3073
crates/core/src/stream.rs (1)
40-40: LGTM!Also applies to: 230-234, 259-263
crates/core/src/api/llm.rs (1)
24-25: LGTM!Also applies to: 324-328, 330-357, 452-537, 539-564
crates/core/src/api/tool.rs (1)
14-14: LGTM!Also applies to: 255-259, 291-367, 369-386
crates/core/src/api/scope.rs (1)
10-12: LGTM!Also applies to: 209-240, 264-302, 328-357
crates/core/src/api/runtime/state.rs (1)
53-58: LGTM! New registries and chain helpers follow the existing_entries/_snapshot_chainpattern used elsewhere in this file, and the guardrail-scope emit paths correctly release locks before invoking sanitizer closures.As per coding guidelines, "Add chain execution helpers to
NemoRelayContextStatefollowing the pattern of existing methods liketool_sanitize_request_chainortool_request_intercepts_chain."Also applies to: 96-98, 557-635
crates/core/tests/fixtures/worker_plugin/src/main.rs (1)
64-94: LGTM!crates/core/tests/integration/worker_plugin_tests.rs (2)
17-19: LGTM!Also applies to: 107-138, 166-169, 179-186, 233-233
282-321: Solid coverage for sanitizer field-preservation semantics.The test correctly demonstrates that
mark_event_fieldsmerges into existingmetadata(bothoriginal_metadataandworker_plugin_marksurvive) while a later-priority sanitizer that assignsfields.datadirectly fully replaces priordata— matching the two fixture guardrails' distinct merge vs. overwrite behaviors.crates/worker/tests/worker_sdk_tests.rs (2)
201-215: Good regression coverage for the (surface, name) duplicate-registration fix.
worker_service_rejects_duplicate_registration_names_on_one_surfaceplusDuplicateEventSanitizerPlugindirectly exercise the fix for the previously-flagged collision risk (same name registered twice onMarkSanitizeGuardrail), and the updatedevent-sanitizename-reuse-across-surfaces assertions confirm cross-surface reuse remains allowed.Also applies to: 258-285, 1466-1479
492-516: LGTM!Also applies to: 1612-1623
crates/worker/src/lib.rs (3)
142-159: Past collision concern resolved via per-surface sanitizer maps.Splitting
mark_sanitizers/scope_start_sanitizers/scope_end_sanitizersinto separate maps, combined withvalidate_unique_registrationsenforcing(surface, name)uniqueness, directly addresses the previously raised concern that mark and scope sanitizers sharing one name-keyed map could silently overwrite each other. Same-name reuse across different event surfaces (as exercised bySurfacePlugin/fixture tests) remains intentionally supported.Also applies to: 200-269, 1552-1567
1046-1051: Duplicate check runs before committing handler state — correct ordering.
validate_unique_registrationsis invoked onctx.handlers.registrationsbeforeself.handlers.lock()is updated, so a rejected duplicate never leaks a partially-overwritten sanitizer map into the live handler state.Also applies to: 1314-1326
1431-1442: LGTM!
|
Nice, as expected the new unit test failed. I think we'll need to patch that |
bbednarski9
left a comment
There was a problem hiding this comment.
Just that unit test failing
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
|
/merge |
#### Overview Extends the built-in PII redaction policy onto the event sanitizer infrastructure from PR #371 so raw PII does not escape through marks or generic scope events. - [x] I confirm this contribution is my own work, or I have the right to submit it under this project's license. - [x] I searched existing issues and open pull requests, and this does not duplicate existing work. #### Details - Broadens `input` to LLM requests and non-tool/LLM scope starts. - Broadens `output` to LLM responses and non-tool/LLM scope ends. - Adds `mark`, defaulting to `true`, with `mark = false` as the opt-out. - Sanitizes `data`, `category_profile`, and `metadata` independently. - Leaves generic tool/LLM scope fields unchanged so specialized sanitizers do not hash or mask twice. - Updates config validation, schema/editor surfaces, and default behavior tests. - Adds a Hermes-style regression across subscribers, ATOF, ATIF, OpenTelemetry, and OpenInference. - Contains no documentation changes; documentation is isolated in a final independent PR. - Breaking changes: none. The intentional default behavior change protects marks when `mark` is omitted. Validation: `nemo-relay-pii-redaction` tests and coverage, relevant CLI/config tests, full Rust and binding matrices, and pre-commit. #### Where should the reviewer start? Start with `crates/pii-redaction/src/component.rs`, `crates/pii-redaction/src/builtin.rs`, and the cross-exporter PII regression in the component tests. #### Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to) - Fixes: RELAY-409 ## Summary by CodeRabbit * **New Features** * Added a new PII redaction surface toggle to mark events (`mark`), defaulting to enabled and configurable via the editor. * Extended built-in sanitization to cover additional scope-level guardrails (start/end) alongside existing LLM/tool sanitization. * **Bug Fixes** * Ensured event/category-profile sanitization is handled correctly, including dropping the category profile when sanitization fails. * **Tests** * Added/expanded unit and security regression tests for mark redaction behavior, metadata correctness, and verification that raw PII never appears in subscribers or telemetry exports. Authors: - Will Killian (https://github.com/willkill07) Approvers: - Bryan Bednarski (https://github.com/bbednarski9) URL: #372
Overview
Adds the shared Rust runtime, plugin, native ABI, and worker protocol infrastructure for sanitizing mark and scope event observability fields without changing existing APIs or ABI v1 offsets.
Warning
BREAKING CHANGE: [Behavioral] Sanitizer Failures are now fail-closed.
If a sanitizer is invoked within the path of any event and fails, the event
being sanitized will be dropped by the Relay runtime. This may result in
missing observability/event data.
If fail-open behavior is desired, then failure logic must be wrapped inside
of a sanitizer itself.
Details
EventSanitizeFieldsfordata,category_profile, andmetadata.Validation:
just test-rust, CI-style Rust coverage (2515 tests), Python/Node/Go binding matrices, formatting, Clippy, and pre-commit.Where should the reviewer start?
Start with
crates/types/src/api/event.rs,crates/core/src/api/registry.rs, and the event sanitizer integration tests incrates/core/tests/integration/api_surface_tests.rs.Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)
Summary by CodeRabbit
New Features
EventSanitizeFields, with new sanitizer guardrail registration APIs for mark events and scope (start/end) events (global and scope-local).Bug Fixes
Tests