Skip to content

feat(sanitizers)!: expose per-call codec capabilities - #546

Merged
rapids-bot[bot] merged 16 commits into
NVIDIA:mainfrom
willkill07:fix/per-call-codec-aware-pii-sanitization
Jul 26, 2026
Merged

feat(sanitizers)!: expose per-call codec capabilities#546
rapids-bot[bot] merged 16 commits into
NVIDIA:mainfrom
willkill07:fix/per-call-codec-aware-pii-sanitization

Conversation

@willkill07

@willkill07 willkill07 commented Jul 23, 2026

Copy link
Copy Markdown
Member

Overview

Exposes the active per-call LLM codec to observability sanitizers across in-process and plugin boundaries, then uses that resolved capability to make PII redaction provider-correct and fail-closed for mixed managed LLM traffic.

Warning

BREAKING CHANGE: LLM request and response sanitizers now use the required two-argument contract (payload, directional_context) -> optional payload. No registration-time compatibility shim remains. Rust, Python, Node.js, native plugins, raw C FFI consumers, worker plugins, and downstream bindings must update their callbacks. All Rust worker sanitizer callbacks—mark, scope, tool, and LLM—are now async. Native dynamic plugins remain ABI v2 and workers remain grpc-v1, but the v2 context/host tables and grpc-v1 invocation/service definitions change in place.

  • 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

  • Replaces split legacy/contextual LLM sanitizer registration with one canonical request and response callback representation while preserving priority, array-order tie breaking, scope ownership, registration rollback, snapshots, and short-circuit omission.
  • Introduces distinct LlmSanitizeRequestContext and LlmSanitizeResponseContext values with structured codec identities: none, built-in, runtime, and opaque. Every active codec, including opaque codecs, can be resolved for the lifetime of the callback.
  • Gives request sanitizers decode(request) and encode(annotated, original); gives response sanitizers decode(response).
  • Extends native ABI v2 and the raw C FFI with borrowed directional codec handles and host-owned transformation operations. Safe wrappers reject retained handles after the callback returns, contain codec panics, preserve ownership for aliased results, and fail closed for malformed output or unrepresentable runtime codec IDs.
  • Extends grpc-v1 with directional contexts and authenticated, invocation-scoped codec capabilities. Host RPCs reject forged, expired, unauthorized, and wrong-direction capability IDs, and SDK authors see async codec proxies rather than raw IDs.
  • Makes Rust worker sanitizer registration async-only while Python workers accept immediate values or awaitables under the same required two-argument callback contract.
  • Keeps sanitizer failures fail-closed for observability: failures or None/null results omit the payload and annotation without changing the client-visible request or response.
  • Invalidates caller-supplied normalized annotations whenever sanitization changes a buffered payload, rebuilding only through the active directional codec. Decode failure or no codec omits the stale annotation.
  • Updates PII redaction to use the resolved active codec per call, use configured codec only when no active codec exists, support provider-agnostic policies without a configured codec, and omit codec-dependent observability data when normalization is unavailable.
  • Hardens normalized target overlays: object-field removals are applied incrementally, unsafe array removals and inconsistent projections fail closed, and OpenAI Responses keeps the top-level output_text alias synchronized with sanitized structured output.
  • Makes Node custom-codec reference cleanup event-loop-affine so early-dropped streams cannot delete N-API references from a Tokio thread.
  • Documents parameter order, directional contexts, codec identity and resolution, capability lifetime, omission behavior, native/worker contracts, and mixed-provider PII usage with Fern tabs. Adds the 0.7 breaking-change release note and a complete 0.6-to-0.7 migration procedure.

Validation:

  • Repository-wide pre-commit suite passed before the final review fixes; the final changed-file pre-commit suite also passed, including FFI header sync, Cargo fmt/Clippy/check, Node formatting, and documentation links.
  • Node: 290 tests passed.
  • Python: 556 tests passed.
  • Go: all package tests passed.
  • Raw FFI: 82 unit tests and 77 integration tests passed.
  • Targeted buffered and streaming OpenAI Responses PII regressions passed and verified serialized events contain no original secret.
  • The public Rust native-plugin example passes its standalone cargo check.
  • The affected Rust core, PII, native-plugin, worker protocol/SDK, and binding capability suites passed. One unrelated CLI test in the workspace was contaminated by an ancestor user plugin configuration; the exact test passed from an isolated checkout of this commit.
  • Documentation build completed with 0 errors.

Where should the reviewer start?

Start with crates/core/src/api/runtime/callbacks.rs and crates/core/src/api/llm.rs for the canonical callback contract, codec propagation, and annotation invalidation. Then review crates/plugin/src/lib.rs, crates/core/src/plugin/dynamic/native.rs, crates/core/src/plugin/dynamic/worker.rs, and crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto for cross-boundary capability lifetime and authorization. Finish with crates/pii-redaction/src/builtin.rs and crates/pii-redaction/src/overlay.rs for per-call codec selection and fail-closed redaction, then review docs/reference/migration-guides.mdx for the public upgrade contract.

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

Summary by CodeRabbit

  • New Features
    • Codec-aware LLM sanitizers: callbacks now receive per-call request/response codec context for directional normalization/redaction.
    • Sanitizers can omit observability payloads/annotations by returning no value (null/None).
    • Codec-aware support expanded across Node.js, Python, Go, Rust, native plugins, and worker integrations.
    • PII redaction now selects the active codec per call for mixed-provider traffic.
  • Breaking Changes
    • Callback signatures changed to (payload, context) and must return an optional payload (null/None to omit).
    • Native plugins now require Native ABI v2 (rebuilt with the matching SDK/protocol).
  • Documentation
    • Added migration guidance and updated middleware/plugin docs for codec-aware sanitizer behavior.

@willkill07
willkill07 requested review from a team as code owners July 23, 2026 21:19
@github-actions github-actions Bot added size:XL PR is extra large Bug issue describes bug; PR fixes bug lang:go PR changes/introduces Go code lang:js PR changes/introduces Javascript/Typescript code lang:python PR changes/introduces Python code lang:rust PR changes/introduces Rust code labels Jul 23, 2026
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: b3c21a90-699c-49f2-88b4-ebee2f6e6ace

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

LLM sanitizers now receive directional per-call codec context, can omit observability payloads, and expose codec operations across runtime, native ABI, worker protocol, Node.js, Python, Go, and plugin integrations. PII redaction uses active codecs with fail-closed normalized-path handling.

Changes

Contextual LLM sanitization

Layer / File(s) Summary
Runtime contracts and event emission
crates/core/src/api/*, crates/core/src/codec/*, crates/core/src/stream.rs
Sanitizer callbacks receive codec context, return optional payloads, short-circuit on omission, and apply omission-aware annotation and stream-finalization rules.
Native ABI and FFI integration
crates/plugin/*, crates/core/src/plugin/dynamic/*, crates/ffi/*
Native ABI v2 and FFI callbacks carry codec identity and scoped codec handles, with request/response codec operations and null-output omission semantics.
Worker protocol and runtime
crates/worker-proto/*, crates/worker/*, crates/core/src/plugin/dynamic/worker.rs
Worker sanitizer invocations carry directional context and temporary authorized codec capabilities through new host RPCs.
Language bindings
crates/node/*, crates/python/*, go/nemo_relay/*, python/*
Node.js, Python, and Go callbacks expose contextual sanitizer APIs, optional results, codec helpers, and callback-scoped lifetime handling.
Active-codec PII redaction
crates/pii-redaction/*
PII redaction selects active per-call codecs, retains configured codecs as compatibility fallbacks, and omits unsafe normalized payloads.
Validation and migration coverage
crates/*/tests/*, go/*_test.go, python/tests/*, docs/*, examples/*
Tests, examples, migration guidance, ABI documentation, and PII configuration documentation cover the updated contracts and failure behavior.

Estimated code review effort: 5 (Critical) | ~180 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LlmRuntime
  participant Sanitizer
  participant Codec
  participant Observability
  LlmRuntime->>Sanitizer: invoke(payload, directional context)
  Sanitizer->>Codec: resolve and transform payload
  Codec-->>Sanitizer: sanitized payload or codec error
  Sanitizer-->>LlmRuntime: payload or omission
  LlmRuntime->>Observability: emit sanitized event or omit payload and annotation
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Matches Conventional Commits and accurately summarizes the codec-capability exposure change.
Description check ✅ Passed The description follows the template sections and includes overview, details, reviewer start point, and related issues.
Linked Issues check ✅ Passed The changes implement per-call codec-aware sanitization, mixed-provider fallback behavior, and updated bindings/docs required by #526.
Out of Scope Changes check ✅ Passed I don't see clear unrelated code changes; the broad edits stay aligned with the codec-aware PII-redaction objective.
Docstring Coverage ✅ Passed Docstring coverage is 86.14% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

License Diff

Compared against origin/main.

Lockfile license changes

Lockfile License Changes

Rust

Added

  • None

Removed

  • None

Updated/Changed

  • None

Node

Added

  • None

Removed

  • None

Updated/Changed

  • None

Python

Added

  • None

Removed

  • None

Updated/Changed

  • None
Status output
[license-diff] selected languages: rust, node, python
[license-diff] generating current inventory
[license-diff] current: generating Rust inventory
[license-diff] current: Rust inventory complete (426 packages)
[license-diff] current: generating Node inventory
[license-diff] current: Node inventory complete (367 packages)
[license-diff] current: generating Python inventory
[license-diff] current: Python inventory complete (105 packages)
[license-diff] current inventory complete
[license-diff] checking out base ref origin/main into a temporary worktree
[license-diff] base: generating Rust inventory
[license-diff] base: Rust inventory complete (426 packages)
[license-diff] base: generating Node inventory
[license-diff] base: Node inventory complete (367 packages)
[license-diff] base: generating Python inventory
[license-diff] base: Python inventory complete (105 packages)
[license-diff] base inventory complete
[license-diff] removing temporary base worktree
[license-diff] comparing inventories
[license-diff] rendering Markdown output
[license-diff] done

@relda88 relda88 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Good improvement overall. One edge case: empty string vs null aren't treated the same downstream — might need a normalization step.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

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/llm.rs (1)

669-769: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Response-side omission gating (payload_omitted) is logically consistent with the request-side handling and with crates/core/src/stream.rs's streaming equivalent — decode/annotation/optimization-summary backfill are all correctly skipped when the payload is omitted.

Minor: data.as_ref().and(response_codec) (line 718) is redundant — resolve_llm_end_annotation already early-returns (None, None) unless both response_codec and data are Some, so passing response_codec directly would be equivalent and simpler.

🤖 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/llm.rs` around lines 669 - 769, In
llm_call_end_with_behavior, simplify the resolve_llm_end_annotation call by
passing response_codec directly instead of the redundant
data.as_ref().and(response_codec) expression; preserve the existing
data.as_ref() argument and payload_omitted gating.
🤖 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/pii-redaction/src/builtin.rs`:
- Around line 446-448: Remove the unnecessary clone in the sanitize response
flow by passing payload by move to sanitize_response_with_codec; payload is not
used after this call, and the subsequent sanitize_json_preorder_dfs mapping
should remain unchanged.
- Around line 393-457: Extract the duplicated omission warning from
llm_sanitize_request_callback and llm_sanitize_response_callback into a shared
helper that accepts the codec context and failure cause. Replace all four
log::warn! sites with this helper, preserving the existing target and context
fields while distinguishing incompatible legacy codec shape from codec
decode/sanitize/encode failure in the message.

In `@crates/python/src/py_callable.rs`:
- Around line 825-862: Add parity diagnostics to
wrap_py_contextual_llm_sanitize_response_fn for context/response serialization
failures, Python callable failures, and result conversion failures, while
retaining fail-closed None returns. Update the final PyLLMRequest extraction
path in wrap_py_contextual_llm_sanitize_request_fn to log extraction errors
before returning None, matching the existing sanitizer wrapper logging style.

In `@python/nemo_relay/guardrails.py`:
- Around line 336-358: Expand the docstrings for
register_contextual_llm_sanitize_request and
register_contextual_llm_sanitize_response to match the Args, Returns, Notes, and
Example structure used by register_llm_sanitize_request and
register_llm_sanitize_response. Document the callback signatures, context
behavior, None handling, and registration return contract without changing
either function’s implementation.

In `@python/tests/plugin/test_worker_sdk.py`:
- Around line 733-741: Remove the redundant explicit return statements from the
nested request_sanitizer and response_sanitizer callbacks, leaving their
existing request/response deletion and seen.append behavior unchanged.

---

Outside diff comments:
In `@crates/core/src/api/llm.rs`:
- Around line 669-769: In llm_call_end_with_behavior, simplify the
resolve_llm_end_annotation call by passing response_codec directly instead of
the redundant data.as_ref().and(response_codec) expression; preserve the
existing data.as_ref() argument and payload_omitted gating.
🪄 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: 7c53ccab-82b5-429b-9a78-7c6b2b4e4bed

📥 Commits

Reviewing files that changed from the base of the PR and between f69802c and 0c12720.

📒 Files selected for processing (58)
  • crates/cli/src/gateway/mod.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/codec/anthropic.rs
  • crates/core/src/codec/openai_chat.rs
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/context/registries.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/src/stream.rs
  • crates/core/tests/unit/context_tests.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/ffi/nemo_relay.h
  • crates/ffi/src/api/llm_registry.rs
  • crates/ffi/src/api/mod.rs
  • crates/ffi/src/api/plugin.rs
  • crates/ffi/src/callable.rs
  • crates/node/plugin.d.ts
  • crates/node/src/api/mod.rs
  • crates/node/src/callable.rs
  • crates/node/tests/llm_tests.mjs
  • crates/pii-redaction/README.md
  • crates/pii-redaction/src/builtin.rs
  • crates/pii-redaction/src/component.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/python/src/py_api/mod.rs
  • crates/python/src/py_callable.rs
  • crates/python/src/py_plugin.rs
  • crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto
  • crates/worker/src/lib.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • docs/about-nemo-relay/concepts/middleware.mdx
  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • docs/build-plugins/language-binding/about.mdx
  • docs/configure-plugins/pii-redaction/about.mdx
  • docs/configure-plugins/pii-redaction/configuration.mdx
  • go/nemo_relay/callbacks.go
  • go/nemo_relay/guardrails/guardrails.go
  • go/nemo_relay/llm_test.go
  • go/nemo_relay/nemo_relay.go
  • go/nemo_relay/plugin.go
  • python/nemo_relay/__init__.py
  • python/nemo_relay/__init__.pyi
  • python/nemo_relay/_native.pyi
  • python/nemo_relay/guardrails.py
  • python/nemo_relay/plugin.py
  • python/nemo_relay/plugin.pyi
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • python/plugin/src/nemo_relay_plugin/_api.py
  • python/tests/plugin/test_public_api_docstrings.py
  • python/tests/plugin/test_worker_sdk.py
💤 Files with no reviewable changes (1)
  • crates/pii-redaction/README.md
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Check / Run
  • GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (55)
**/*.mdx

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

MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)

In MDX files, top-of-file comments must use JSX comment delimiters ({/* to open and */} to close); do not use HTML comments for MDX SPDX headers

Files:

  • docs/configure-plugins/pii-redaction/about.mdx
  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • docs/about-nemo-relay/concepts/middleware.mdx
  • docs/build-plugins/language-binding/about.mdx
  • docs/configure-plugins/pii-redaction/configuration.mdx
**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

Update README.md, fern/, package READMEs, and binding-support notes when public behavior, package names, examples, or supported bindings change.

**/*.{md,mdx}: Prefer the documented public API, not internal shortcuts
Keep package names, repo references, and build commands current
Keep release-process and release-notes guidance in repo-maintainer docs such as RELEASING.md, not as user-facing docs pages or CHANGELOG.md
Keep stable user-facing wrappers at scripts/ root in docs and examples; only point at namespaced helper paths when documenting internal maintenance work
When detailed dynamic plugin guides exist, keep Rust native plugin examples, Python worker plugin examples, and grpc-v1 protocol details on separate pages

If links in documentation change, run just docs-linkcheck.

Files:

  • docs/configure-plugins/pii-redaction/about.mdx
  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • docs/about-nemo-relay/concepts/middleware.mdx
  • docs/build-plugins/language-binding/about.mdx
  • docs/configure-plugins/pii-redaction/configuration.mdx
**/*.{md,markdown,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add the SPDX license header to all Markdown/MDX documentation files using the HTML comment block form.

Files:

  • docs/configure-plugins/pii-redaction/about.mdx
  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • docs/about-nemo-relay/concepts/middleware.mdx
  • docs/build-plugins/language-binding/about.mdx
  • docs/configure-plugins/pii-redaction/configuration.mdx
{docs,examples}/**/*

📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)

Update docs and examples.

Files:

  • docs/configure-plugins/pii-redaction/about.mdx
  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • docs/about-nemo-relay/concepts/middleware.mdx
  • docs/build-plugins/language-binding/about.mdx
  • docs/configure-plugins/pii-redaction/configuration.mdx
**/*

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

**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, use maintain-dynamic-plugins and include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, prefer uv run pre-commit run --files <changed files...>.
Before review or handoff, run uv run pre-commit run --all-files.

Files:

  • docs/configure-plugins/pii-redaction/about.mdx
  • crates/cli/src/gateway/mod.rs
  • python/tests/plugin/test_public_api_docstrings.py
  • crates/core/tests/unit/context_tests.rs
  • crates/core/src/api/runtime.rs
  • crates/ffi/src/api/mod.rs
  • crates/core/src/codec/traits.rs
  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • crates/core/src/codec/anthropic.rs
  • docs/about-nemo-relay/concepts/middleware.mdx
  • python/nemo_relay/plugin.py
  • crates/node/plugin.d.ts
  • crates/core/src/codec/openai_responses.rs
  • docs/build-plugins/language-binding/about.mdx
  • python/nemo_relay/plugin.pyi
  • crates/core/src/codec/openai_chat.rs
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/core/src/context/registries.rs
  • python/nemo_relay/__init__.pyi
  • crates/node/tests/llm_tests.mjs
  • python/nemo_relay/__init__.py
  • crates/python/src/py_api/mod.rs
  • go/nemo_relay/llm_test.go
  • python/nemo_relay/_native.pyi
  • crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto
  • go/nemo_relay/guardrails/guardrails.go
  • crates/python/src/py_callable.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/ffi/src/api/llm_registry.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/stream.rs
  • crates/node/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • python/nemo_relay/guardrails.py
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • docs/configure-plugins/pii-redaction/configuration.mdx
  • crates/core/src/plugin.rs
  • crates/node/src/api/mod.rs
  • crates/core/src/api/registry.rs
  • go/nemo_relay/nemo_relay.go
  • crates/core/src/plugin/dynamic/worker.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/pii-redaction/src/builtin.rs
  • crates/ffi/nemo_relay.h
  • go/nemo_relay/plugin.go
  • crates/plugin/src/lib.rs
  • go/nemo_relay/callbacks.go
  • crates/core/src/api/runtime/state.rs
  • crates/pii-redaction/src/component.rs
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/plugin.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
  • crates/core/src/api/llm.rs
  • crates/plugin/tests/typed_callbacks.rs
docs/**/*

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

If documentation examples or commands under docs/ change, run the targeted docs checks appropriate to the change.

Files:

  • docs/configure-plugins/pii-redaction/about.mdx
  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • docs/about-nemo-relay/concepts/middleware.mdx
  • docs/build-plugins/language-binding/about.mdx
  • docs/configure-plugins/pii-redaction/configuration.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}: Review documentation for technical accuracy against the current API, command correctness, and consistency across language bindings.
Flag stale examples, missing SPDX headers where required, and instructions that no longer match CI or pre-commit behavior.

Files:

  • docs/configure-plugins/pii-redaction/about.mdx
  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • docs/about-nemo-relay/concepts/middleware.mdx
  • docs/build-plugins/language-binding/about.mdx
  • docs/configure-plugins/pii-redaction/configuration.mdx
**/*.rs

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

**/*.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

When changing the core Rust runtime or Rust-facing API surface, format Rust code with cargo fmt (rustfmt defaults), keep cargo clippy -- -D warnings clean, and satisfy cargo deny check per deny.toml.

**/*.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.
For Rust changes headed for review, run cargo fmt --all and cargo clippy --workspace --all-targets -- -D warnings even if relying on pre-commit.

Files:

  • crates/cli/src/gateway/mod.rs
  • crates/core/tests/unit/context_tests.rs
  • crates/core/src/api/runtime.rs
  • crates/ffi/src/api/mod.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/core/src/context/registries.rs
  • crates/python/src/py_api/mod.rs
  • crates/python/src/py_callable.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/ffi/src/api/llm_registry.rs
  • crates/core/src/stream.rs
  • crates/node/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin.rs
  • crates/node/src/api/mod.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/pii-redaction/src/builtin.rs
  • crates/plugin/src/lib.rs
  • crates/core/src/api/runtime/state.rs
  • crates/pii-redaction/src/component.rs
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/plugin.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
  • crates/core/src/api/llm.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.{rs,py}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions in Rust and Python: use snake_case.

Files:

  • crates/cli/src/gateway/mod.rs
  • python/tests/plugin/test_public_api_docstrings.py
  • crates/core/tests/unit/context_tests.rs
  • crates/core/src/api/runtime.rs
  • crates/ffi/src/api/mod.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • python/nemo_relay/plugin.py
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/core/src/context/registries.rs
  • python/nemo_relay/__init__.py
  • crates/python/src/py_api/mod.rs
  • crates/python/src/py_callable.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/ffi/src/api/llm_registry.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/stream.rs
  • crates/node/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • python/nemo_relay/guardrails.py
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin.rs
  • crates/node/src/api/mod.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/pii-redaction/src/builtin.rs
  • crates/plugin/src/lib.rs
  • crates/core/src/api/runtime/state.rs
  • crates/pii-redaction/src/component.rs
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/plugin.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
  • crates/core/src/api/llm.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,js,mjs,cjs,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{rs,py,js,mjs,cjs,ts,tsx}: 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, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.

Files:

  • crates/cli/src/gateway/mod.rs
  • python/tests/plugin/test_public_api_docstrings.py
  • crates/core/tests/unit/context_tests.rs
  • crates/core/src/api/runtime.rs
  • crates/ffi/src/api/mod.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • python/nemo_relay/plugin.py
  • crates/node/plugin.d.ts
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/core/src/context/registries.rs
  • crates/node/tests/llm_tests.mjs
  • python/nemo_relay/__init__.py
  • crates/python/src/py_api/mod.rs
  • crates/python/src/py_callable.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/ffi/src/api/llm_registry.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/stream.rs
  • crates/node/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • python/nemo_relay/guardrails.py
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin.rs
  • crates/node/src/api/mod.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/pii-redaction/src/builtin.rs
  • crates/plugin/src/lib.rs
  • crates/core/src/api/runtime/state.rs
  • crates/pii-redaction/src/component.rs
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/plugin.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
  • crates/core/src/api/llm.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts,c,h}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use language-appropriate naming conventions: Rust snake_case, C FFI exports prefixed nemo_relay_, Go PascalCase, Node.js camelCase, and Python snake_case.

Files:

  • crates/cli/src/gateway/mod.rs
  • python/tests/plugin/test_public_api_docstrings.py
  • crates/core/tests/unit/context_tests.rs
  • crates/core/src/api/runtime.rs
  • crates/ffi/src/api/mod.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • python/nemo_relay/plugin.py
  • crates/node/plugin.d.ts
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/core/src/context/registries.rs
  • python/nemo_relay/__init__.py
  • crates/python/src/py_api/mod.rs
  • go/nemo_relay/llm_test.go
  • go/nemo_relay/guardrails/guardrails.go
  • crates/python/src/py_callable.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/ffi/src/api/llm_registry.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/stream.rs
  • crates/node/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • python/nemo_relay/guardrails.py
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin.rs
  • crates/node/src/api/mod.rs
  • crates/core/src/api/registry.rs
  • go/nemo_relay/nemo_relay.go
  • crates/core/src/plugin/dynamic/worker.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/pii-redaction/src/builtin.rs
  • crates/ffi/nemo_relay.h
  • go/nemo_relay/plugin.go
  • crates/plugin/src/lib.rs
  • go/nemo_relay/callbacks.go
  • crates/core/src/api/runtime/state.rs
  • crates/pii-redaction/src/component.rs
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/plugin.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
  • crates/core/src/api/llm.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.{rs,go,js,ts}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding // comment form.

Files:

  • crates/cli/src/gateway/mod.rs
  • crates/core/tests/unit/context_tests.rs
  • crates/core/src/api/runtime.rs
  • crates/ffi/src/api/mod.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • crates/node/plugin.d.ts
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/core/src/context/registries.rs
  • crates/python/src/py_api/mod.rs
  • go/nemo_relay/llm_test.go
  • go/nemo_relay/guardrails/guardrails.go
  • crates/python/src/py_callable.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/ffi/src/api/llm_registry.rs
  • crates/core/src/stream.rs
  • crates/node/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin.rs
  • crates/node/src/api/mod.rs
  • crates/core/src/api/registry.rs
  • go/nemo_relay/nemo_relay.go
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/pii-redaction/src/builtin.rs
  • go/nemo_relay/plugin.go
  • crates/plugin/src/lib.rs
  • go/nemo_relay/callbacks.go
  • crates/core/src/api/runtime/state.rs
  • crates/pii-redaction/src/component.rs
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/plugin.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
  • crates/core/src/api/llm.rs
  • crates/plugin/tests/typed_callbacks.rs
{crates/**/src/**/*.rs,python/**/*.py}

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

Do not add tests under src; Rust tests belong in crate tests/ trees, and Python SDK tests belong under python/tests.

Files:

  • crates/cli/src/gateway/mod.rs
  • python/tests/plugin/test_public_api_docstrings.py
  • crates/core/src/api/runtime.rs
  • crates/ffi/src/api/mod.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • python/nemo_relay/plugin.py
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • crates/core/src/context/registries.rs
  • python/nemo_relay/__init__.py
  • crates/python/src/py_api/mod.rs
  • crates/python/src/py_callable.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/ffi/src/api/llm_registry.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/stream.rs
  • crates/node/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • python/nemo_relay/guardrails.py
  • crates/core/src/plugin.rs
  • crates/node/src/api/mod.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/pii-redaction/src/builtin.rs
  • crates/plugin/src/lib.rs
  • crates/core/src/api/runtime/state.rs
  • crates/pii-redaction/src/component.rs
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/plugin.rs
  • crates/worker/src/lib.rs
  • crates/core/src/api/llm.rs
**/*.{rs,py,go,js,ts}

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

If a language surface changed, always run that language's test target even when Rust core did not change.

Files:

  • crates/cli/src/gateway/mod.rs
  • python/tests/plugin/test_public_api_docstrings.py
  • crates/core/tests/unit/context_tests.rs
  • crates/core/src/api/runtime.rs
  • crates/ffi/src/api/mod.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • python/nemo_relay/plugin.py
  • crates/node/plugin.d.ts
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/core/src/context/registries.rs
  • python/nemo_relay/__init__.py
  • crates/python/src/py_api/mod.rs
  • go/nemo_relay/llm_test.go
  • go/nemo_relay/guardrails/guardrails.go
  • crates/python/src/py_callable.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/ffi/src/api/llm_registry.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/stream.rs
  • crates/node/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • python/nemo_relay/guardrails.py
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin.rs
  • crates/node/src/api/mod.rs
  • crates/core/src/api/registry.rs
  • go/nemo_relay/nemo_relay.go
  • crates/core/src/plugin/dynamic/worker.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/pii-redaction/src/builtin.rs
  • go/nemo_relay/plugin.go
  • crates/plugin/src/lib.rs
  • go/nemo_relay/callbacks.go
  • crates/core/src/api/runtime/state.rs
  • crates/pii-redaction/src/component.rs
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/plugin.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
  • crates/core/src/api/llm.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,js,ts,tsx,go,java,kt,swift}

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.

Files:

  • crates/cli/src/gateway/mod.rs
  • python/tests/plugin/test_public_api_docstrings.py
  • crates/core/tests/unit/context_tests.rs
  • crates/core/src/api/runtime.rs
  • crates/ffi/src/api/mod.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • python/nemo_relay/plugin.py
  • crates/node/plugin.d.ts
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/core/src/context/registries.rs
  • python/nemo_relay/__init__.py
  • crates/python/src/py_api/mod.rs
  • go/nemo_relay/llm_test.go
  • go/nemo_relay/guardrails/guardrails.go
  • crates/python/src/py_callable.rs
  • crates/python/src/py_plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/ffi/src/api/llm_registry.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/stream.rs
  • crates/node/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • python/nemo_relay/guardrails.py
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin.rs
  • crates/node/src/api/mod.rs
  • crates/core/src/api/registry.rs
  • go/nemo_relay/nemo_relay.go
  • crates/core/src/plugin/dynamic/worker.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/pii-redaction/src/builtin.rs
  • go/nemo_relay/plugin.go
  • crates/plugin/src/lib.rs
  • go/nemo_relay/callbacks.go
  • crates/core/src/api/runtime/state.rs
  • crates/pii-redaction/src/component.rs
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/plugin.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
  • crates/core/src/api/llm.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.py: When changing the Python wrapper package, tests, or docs tooling, lint with Ruff (E, F, W, I), format with Ruff formatter (120-character lines, double quotes), and pass ty type checking.
Add the SPDX license header to all Python source files using the # comment form.

Files:

  • python/tests/plugin/test_public_api_docstrings.py
  • python/nemo_relay/plugin.py
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • python/nemo_relay/__init__.py
  • python/tests/plugin/test_worker_sdk.py
  • python/nemo_relay/guardrails.py
  • python/plugin/src/nemo_relay_plugin/_api.py
**/*.{py,go,js,ts}

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

Keep Python, Go, and Node.js config objects and subscriber/exporter methods aligned so all bindings expose the same logical knobs and semantics.

Files:

  • python/tests/plugin/test_public_api_docstrings.py
  • python/nemo_relay/plugin.py
  • crates/node/plugin.d.ts
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • python/nemo_relay/__init__.py
  • go/nemo_relay/llm_test.go
  • go/nemo_relay/guardrails/guardrails.go
  • python/tests/plugin/test_worker_sdk.py
  • python/nemo_relay/guardrails.py
  • go/nemo_relay/nemo_relay.go
  • python/plugin/src/nemo_relay_plugin/_api.py
  • go/nemo_relay/plugin.go
  • go/nemo_relay/callbacks.go
python/tests/**/*.py

📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)

python/tests/**/*.py: Pytest is used to run tests.
Do not add @pytest.mark.asyncio to any test; async tests are automatically detected and run by the async runner.
Do not add a -> None return type annotation to test functions.
When mocking a class, do not define a new class; use unittest.mock.MagicMock or unittest.mock.AsyncMock, with the spec constructor argument when necessary.
Name mocked classes with the mock prefix, not fake.
Prefer pytest fixtures over helper methods.
Do not repeat fixtures; if a fixture is needed in multiple test files, place it in a conftest.py file.
When creating a fixture, use @pytest.fixture(name="<fixture_name>"[, scope="<scope>"]) and define the fixture function as def <fixture_name>_fixture() -> <return_type>:; only specify scope when it is not function.
Prefer pytest.mark.parametrize over creating individual tests for different input types.

Files:

  • python/tests/plugin/test_public_api_docstrings.py
  • python/tests/plugin/test_worker_sdk.py
{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:

  • python/tests/plugin/test_public_api_docstrings.py
  • crates/core/tests/unit/context_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/node/tests/llm_tests.mjs
  • go/nemo_relay/llm_test.go
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
  • crates/plugin/tests/typed_callbacks.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/context_tests.rs
  • crates/core/src/api/runtime.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • crates/core/src/context/registries.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.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

Files:

  • crates/core/tests/unit/context_tests.rs
  • crates/core/src/api/runtime.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • crates/core/src/context/registries.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
crates/{core,adaptive}/**/*

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

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

Files:

  • crates/core/tests/unit/context_tests.rs
  • crates/core/src/api/runtime.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • crates/core/src/context/registries.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.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/context_tests.rs
  • crates/core/src/api/runtime.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • crates/core/src/context/registries.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
crates/core/src/{api/**/*.rs,api/runtime/**/*.rs,codec/**/*.rs,json.rs}

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Implement the new or changed public runtime behavior first in the Rust core, especially under crates/core/src/api/ and related core modules such as crates/core/src/api/runtime/, crates/core/src/codec/, and crates/core/src/json.rs.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/codec/anthropic.rs
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/openai_chat.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
crates/core/src/api/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Preserve the documented pipeline order: conditional guardrails, request intercepts, request sanitization, execution intercepts, and response sanitization for tool and LLM execution; specialized sanitization, event creation, and dispatch for mark and scope events.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
crates/ffi/**

📄 CodeRabbit inference engine (.agents/skills/test-ffi-surface/SKILL.md)

Rebuild the FFI crate in release mode so the shared library and header stay in sync when making changes to crates/ffi

Files:

  • crates/ffi/src/api/mod.rs
  • crates/ffi/src/api/llm_registry.rs
  • crates/ffi/nemo_relay.h
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/plugin.rs
crates/ffi/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)

If the change touched crates/ffi, also use test-ffi-surface for validation

Use C FFI export names prefixed with nemo_relay_ in the raw C FFI layer.

Files:

  • crates/ffi/src/api/mod.rs
  • crates/ffi/src/api/llm_registry.rs
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/plugin.rs
{crates/ffi/src/api/*.rs,crates/ffi/nemo_relay.h}

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Add or update the shared C/FFI surface in the relevant crates/ffi/src/api/*.rs module, re-export it through crates/ffi/src/api/mod.rs, and keep the generated crates/ffi/nemo_relay.h header correct.

Files:

  • crates/ffi/src/api/mod.rs
  • crates/ffi/src/api/llm_registry.rs
  • crates/ffi/nemo_relay.h
  • crates/ffi/src/api/plugin.rs
crates/{python,ffi,node}/**/*

⚙️ CodeRabbit configuration file

crates/{python,ffi,node}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.

Files:

  • crates/ffi/src/api/mod.rs
  • crates/node/plugin.d.ts
  • crates/node/tests/llm_tests.mjs
  • crates/python/src/py_api/mod.rs
  • crates/python/src/py_callable.rs
  • crates/python/src/py_plugin.rs
  • crates/ffi/src/api/llm_registry.rs
  • crates/node/src/callable.rs
  • crates/node/src/api/mod.rs
  • crates/ffi/nemo_relay.h
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/plugin.rs
{crates/core/src/plugin/dynamic/**,crates/plugin/**,crates/worker/**,crates/worker-proto/**,crates/types/**,python/plugin/**,examples/rust-native-plugin/**,examples/python-grpc-worker-plugin/**,docs/build-plugins/**}

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

Keep the stable boundary explicit: native plugins cross a C ABI, and worker plugins cross grpc-v1.

Files:

  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • docs/build-plugins/language-binding/about.mdx
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/plugin/src/lib.rs
  • crates/worker/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
{crates/core/src/plugin/dynamic/**,examples/rust-native-plugin/**,examples/python-grpc-worker-plugin/**,docs/build-plugins/**}

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

Native and worker plugins are trusted extensions; document that native plugins are in-process and unsandboxed, and worker plugins provide process isolation but not a security sandbox.

Files:

  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • docs/build-plugins/language-binding/about.mdx
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/src/plugin/dynamic/worker.rs
{docs/build-plugins/**,examples/rust-native-plugin/**,examples/python-grpc-worker-plugin/**}

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

When detailed dynamic plugin guides exist, keep Rust native, Python worker, and grpc-v1 protocol details on separate pages.

Files:

  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • docs/build-plugins/language-binding/about.mdx
python/nemo_relay/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Python wrapper modules live under python/nemo_relay/, and the native extension is built from crates/python with maturin.

Files:

  • python/nemo_relay/plugin.py
  • python/nemo_relay/__init__.py
  • python/nemo_relay/guardrails.py
{crates/python/src/py_api/mod.rs,python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi,go/nemo_relay/**/*.go,crates/node/src/api/**/*.rs}

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Update the language-native bindings for every exposed surface in Python, Go, and Node.js.

Files:

  • python/nemo_relay/plugin.py
  • python/nemo_relay/plugin.pyi
  • python/nemo_relay/__init__.pyi
  • python/nemo_relay/__init__.py
  • crates/python/src/py_api/mod.rs
  • go/nemo_relay/llm_test.go
  • python/nemo_relay/_native.pyi
  • go/nemo_relay/guardrails/guardrails.go
  • python/nemo_relay/guardrails.py
  • crates/node/src/api/mod.rs
  • go/nemo_relay/nemo_relay.go
  • go/nemo_relay/plugin.go
  • go/nemo_relay/callbacks.go
{python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi,go/nemo_relay/**/*.go}

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Update language wrapper helpers such as Python wrapper modules, Python type stubs, and Go shorthand packages when the new behavior belongs in those helper layers.

Files:

  • python/nemo_relay/plugin.py
  • python/nemo_relay/plugin.pyi
  • python/nemo_relay/__init__.pyi
  • python/nemo_relay/__init__.py
  • go/nemo_relay/llm_test.go
  • python/nemo_relay/_native.pyi
  • go/nemo_relay/guardrails/guardrails.go
  • python/nemo_relay/guardrails.py
  • go/nemo_relay/nemo_relay.go
  • go/nemo_relay/plugin.go
  • go/nemo_relay/callbacks.go
python/nemo_relay/{adaptive.py,plugin.py}

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

Keep Python adaptive/plugin wrappers in python/nemo_relay/adaptive.py and python/nemo_relay/plugin.py synchronized with the shared adaptive/plugin boundary and lifecycle.

Files:

  • python/nemo_relay/plugin.py
python/nemo_relay/**/*

⚙️ CodeRabbit configuration file

python/nemo_relay/**/*: Review Python wrapper changes for typed API consistency, contextvars-based scope isolation, async behavior, and parity with the native extension.
Stubs and runtime implementations should stay aligned.

Files:

  • python/nemo_relay/plugin.py
  • python/nemo_relay/plugin.pyi
  • python/nemo_relay/__init__.pyi
  • python/nemo_relay/__init__.py
  • python/nemo_relay/_native.pyi
  • python/nemo_relay/guardrails.py
crates/node/**/*.{js,ts,jsx,tsx,json}

📄 CodeRabbit inference engine (.agents/skills/test-node-binding/SKILL.md)

Format changed Node files with npm run format --workspace=nemo-relay-node

Files:

  • crates/node/plugin.d.ts
crates/node/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.agents/skills/test-node-binding/SKILL.md)

Use npm run check:docstrings --workspace=nemo-relay-node to validate public API docstring checks when surface docs changed

Files:

  • crates/node/plugin.d.ts
crates/node/**/*.{js,mjs,cjs,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use camelCase for Node.js public APIs.

Files:

  • crates/node/plugin.d.ts
  • crates/node/tests/llm_tests.mjs
{crates/core/src/plugin/dynamic/**/*.rs,crates/plugin/**/*.rs,crates/worker/**/*.rs,crates/worker-proto/**/*.rs,python/plugin/**/*.py}

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

Manifest validation must cover kind, compatibility, load contract, integrity, capability mismatch, and disabled-plugin behavior.

Files:

  • python/plugin/src/nemo_relay_plugin/__init__.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/plugin/src/lib.rs
  • crates/worker/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
{crates/plugin/**/*.rs,python/plugin/**/*.py}

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

Rust and Python SDKs must expose every supported registration surface.

Files:

  • python/plugin/src/nemo_relay_plugin/__init__.py
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
{crates/worker-proto/**/*.{rs,proto},crates/worker/**/*.rs}

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

Keep worker protocol DTOs in JsonEnvelope; protobuf should own control flow, not duplicated Relay data models.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
  • crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto
  • crates/worker/src/lib.rs
crates/worker/**/*.rs

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

Worker activation must cover process launch, token authentication, handshake, validation, declarative registration, proxy rollback, cancellation, and shutdown.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
  • crates/worker/src/lib.rs
go/nemo_relay/**/*.go

📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)

go/nemo_relay/**/*.go: Format changed Go packages with cd go/nemo_relay && go fmt ./...
Run Go tests with just test-go to build and test the NeMo Relay Go binding
Use just build-go when you want an explicit build-only pass or need the artifact for other work
Use just ci=true test-go when you need the CI-style coverage and JUnit path
On macOS, set DYLD_LIBRARY_PATH to the ../../target/release directory before running the raw go test command directly

Use PascalCase for public Go APIs.

Files:

  • go/nemo_relay/llm_test.go
  • go/nemo_relay/guardrails/guardrails.go
  • go/nemo_relay/nemo_relay.go
  • go/nemo_relay/plugin.go
  • go/nemo_relay/callbacks.go
**/*.go

📄 CodeRabbit inference engine (CONTRIBUTING.md)

When changing the experimental Go binding, format Go code with gofmt and keep go vet ./... passing.

Files:

  • go/nemo_relay/llm_test.go
  • go/nemo_relay/guardrails/guardrails.go
  • go/nemo_relay/nemo_relay.go
  • go/nemo_relay/plugin.go
  • go/nemo_relay/callbacks.go
go/nemo_relay/**

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

Keep shared plugin helpers in go/nemo_relay aligned with plugin registration, composition, and lifecycle behavior.

Files:

  • go/nemo_relay/llm_test.go
  • go/nemo_relay/guardrails/guardrails.go
  • go/nemo_relay/nemo_relay.go
  • go/nemo_relay/plugin.go
  • go/nemo_relay/callbacks.go
go/nemo_relay/**/*

⚙️ CodeRabbit configuration file

go/nemo_relay/**/*: Review Go binding changes for cgo memory ownership, race safety, callback cleanup, idiomatic exported APIs, and parity with Rust/FFI behavior.
Any API change should include focused Go tests and consider race-test behavior.

Files:

  • go/nemo_relay/llm_test.go
  • go/nemo_relay/guardrails/guardrails.go
  • go/nemo_relay/nemo_relay.go
  • go/nemo_relay/plugin.go
  • go/nemo_relay/callbacks.go
crates/core/src/api/runtime/callbacks.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Define or reuse the middleware callback type alias in crates/core/src/api/runtime/callbacks.rs, using the appropriate callable signature and thread-safety bounds.

Files:

  • crates/core/src/api/runtime/callbacks.rs
{crates/core/src/plugin/dynamic/**/*.rs,examples/rust-native-plugin/**/*.rs}

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

Do not pass Rust runtime types, trait objects, futures, or allocator-owned strings across the native dynamic-library boundary.

Files:

  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/src/plugin/dynamic/worker.rs
crates/core/src/plugin/dynamic/**/*.rs

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

The native loader must keep libraries alive until registered callbacks are cleared and must deregister plugin kinds before unload.

Files:

  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/src/plugin/dynamic/worker.rs
crates/core/src/api/registry.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Add global and scope-local registration and deregistration APIs using the existing global_*_registry_api! and scope_*_registry_api! macro patterns, unless the design explicitly excludes one scope.

Files:

  • crates/core/src/api/registry.rs
crates/ffi/nemo_relay.h

📄 CodeRabbit inference engine (.agents/skills/test-ffi-surface/SKILL.md)

Check the generated header diff when any exported symbol or type changed in the FFI surface

Update generated or generated-from-build surfaces such as crates/ffi/nemo_relay.h through the proper build step.

Files:

  • crates/ffi/nemo_relay.h
crates/core/src/api/runtime/state.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

crates/core/src/api/runtime/state.rs: Add a SortedRegistry<GuardrailEntry<...>> or SortedRegistry<Intercept<...>> field to NemoRelayContextState for the new middleware type.
Add chain-execution helpers to NemoRelayContextState, following existing helpers such as tool_sanitize_request_chain or tool_request_intercepts_chain.

Files:

  • crates/core/src/api/runtime/state.rs
crates/core/src/api/{tool,llm,shared,scope}.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Wire the new middleware chain into the appropriate lifecycle owner and pipeline stage: tool and LLM execution paths use tool.rs or llm.rs; shared mark and scope event sanitization uses shared.rs and is called from scope.rs.

Files:

  • crates/core/src/api/llm.rs
🧠 Learnings (1)
📚 Learning: 2026-05-07T18:04:44.387Z
Learnt from: mnajafian-nv
Repo: NVIDIA/NeMo-Flow PR: 67
File: integrations/openclaw/src/modules.ts:1-2
Timestamp: 2026-05-07T18:04:44.387Z
Learning: In NVIDIA/NeMo-Flow, TypeScript source files should use `//` line comments for SPDX headers (e.g., `// SPDX-FileCopyrightText: ...` and `// SPDX-License-Identifier: ...`) rather than C-style block comments (`/* ... */`). The repo’s copyright checker enforces this mapping, so `//` SPDX headers in `.ts` files should not be flagged as a style violation.

Applied to files:

  • crates/node/plugin.d.ts
🪛 Ruff (0.15.21)
python/tests/plugin/test_worker_sdk.py

[warning] 736-736: Do not explicitly return None in function if it is the only possible return value

Remove explicit return None

(RET501)


[warning] 736-736: Useless return statement at end of function

Remove useless return statement

(PLR1711)


[warning] 741-741: Do not explicitly return None in function if it is the only possible return value

Remove explicit return None

(RET501)


[warning] 741-741: Useless return statement at end of function

Remove useless return statement

(PLR1711)

Comment thread crates/pii-redaction/src/builtin.rs
Comment thread crates/pii-redaction/src/builtin.rs Outdated
Comment thread crates/python/src/py_callable.rs Outdated
Comment thread python/nemo_relay/guardrails.py Outdated
Comment thread python/tests/plugin/test_worker_sdk.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/core/src/api/llm.rs (1)

431-466: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Tie annotations to the sanitized payload before publishing events.

Both paths can retain annotations created from the original payload after contextual sanitization changes or omits that payload.

  • crates/core/src/api/llm.rs#L431-L466: clear annotated_request when the request changes and cannot be safely re-decoded.
  • crates/core/src/api/llm.rs#L702-L723: clear or regenerate annotated_response unless it is guaranteed to describe the sanitized response.
🤖 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/llm.rs` around lines 431 - 466, Ensure published
annotations always describe the sanitized payload: in
crates/core/src/api/llm.rs:431-466, clear annotated_request when sanitization
changes the request but codec decoding fails, rather than retaining annotations
from the original request; in crates/core/src/api/llm.rs:702-723, clear or
regenerate annotated_response unless it is guaranteed to correspond to the
sanitized response before building the event.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@crates/core/src/api/llm.rs`:
- Around line 431-466: Ensure published annotations always describe the
sanitized payload: in crates/core/src/api/llm.rs:431-466, clear
annotated_request when sanitization changes the request but codec decoding
fails, rather than retaining annotations from the original request; in
crates/core/src/api/llm.rs:702-723, clear or regenerate annotated_response
unless it is guaranteed to correspond to the sanitized response before building
the event.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 4069591c-b48f-42dc-b657-5e4158d4e367

📥 Commits

Reviewing files that changed from the base of the PR and between 0c12720 and 3df2b80.

📒 Files selected for processing (7)
  • crates/core/src/api/llm.rs
  • crates/pii-redaction/src/builtin.rs
  • crates/python/src/py_callable.rs
  • crates/worker/src/lib.rs
  • python/nemo_relay/guardrails.py
  • python/plugin/src/nemo_relay_plugin/_api.py
  • python/tests/plugin/test_worker_sdk.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (30)
**/*.{rs,py}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions in Rust and Python: use snake_case.

Files:

  • python/nemo_relay/guardrails.py
  • crates/python/src/py_callable.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/api/llm.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/src/builtin.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
**/*.{rs,py,js,mjs,cjs,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{rs,py,js,mjs,cjs,ts,tsx}: 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, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.

Files:

  • python/nemo_relay/guardrails.py
  • crates/python/src/py_callable.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/api/llm.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/src/builtin.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
python/nemo_relay/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Python wrapper modules live under python/nemo_relay/, and the native extension is built from crates/python with maturin.

Files:

  • python/nemo_relay/guardrails.py
**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.py: When changing the Python wrapper package, tests, or docs tooling, lint with Ruff (E, F, W, I), format with Ruff formatter (120-character lines, double quotes), and pass ty type checking.
Add the SPDX license header to all Python source files using the # comment form.

Files:

  • python/nemo_relay/guardrails.py
  • python/tests/plugin/test_worker_sdk.py
  • python/plugin/src/nemo_relay_plugin/_api.py
**/*.{rs,py,go,js,ts,c,h}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use language-appropriate naming conventions: Rust snake_case, C FFI exports prefixed nemo_relay_, Go PascalCase, Node.js camelCase, and Python snake_case.

Files:

  • python/nemo_relay/guardrails.py
  • crates/python/src/py_callable.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/api/llm.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/src/builtin.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
{crates/python/src/py_api/mod.rs,python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi,go/nemo_relay/**/*.go,crates/node/src/api/**/*.rs}

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Update the language-native bindings for every exposed surface in Python, Go, and Node.js.

Files:

  • python/nemo_relay/guardrails.py
{python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi,go/nemo_relay/**/*.go}

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Update language wrapper helpers such as Python wrapper modules, Python type stubs, and Go shorthand packages when the new behavior belongs in those helper layers.

Files:

  • python/nemo_relay/guardrails.py
{crates/**/src/**/*.rs,python/**/*.py}

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

Do not add tests under src; Rust tests belong in crate tests/ trees, and Python SDK tests belong under python/tests.

Files:

  • python/nemo_relay/guardrails.py
  • crates/python/src/py_callable.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/api/llm.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/src/builtin.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
**/*.{py,go,js,ts}

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

Keep Python, Go, and Node.js config objects and subscriber/exporter methods aligned so all bindings expose the same logical knobs and semantics.

Files:

  • python/nemo_relay/guardrails.py
  • python/tests/plugin/test_worker_sdk.py
  • python/plugin/src/nemo_relay_plugin/_api.py
**/*

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

**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, use maintain-dynamic-plugins and include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, prefer uv run pre-commit run --files <changed files...>.
Before review or handoff, run uv run pre-commit run --all-files.

Files:

  • python/nemo_relay/guardrails.py
  • crates/python/src/py_callable.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/api/llm.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/src/builtin.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
**/*.{rs,py,go,js,ts}

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

If a language surface changed, always run that language's test target even when Rust core did not change.

Files:

  • python/nemo_relay/guardrails.py
  • crates/python/src/py_callable.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/api/llm.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/src/builtin.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
**/*.{rs,py,js,ts,tsx,go,java,kt,swift}

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.

Files:

  • python/nemo_relay/guardrails.py
  • crates/python/src/py_callable.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/core/src/api/llm.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/src/builtin.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
python/nemo_relay/**/*

⚙️ CodeRabbit configuration file

python/nemo_relay/**/*: Review Python wrapper changes for typed API consistency, contextvars-based scope isolation, async behavior, and parity with the native extension.
Stubs and runtime implementations should stay aligned.

Files:

  • python/nemo_relay/guardrails.py
**/*.rs

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

**/*.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

When changing the core Rust runtime or Rust-facing API surface, format Rust code with cargo fmt (rustfmt defaults), keep cargo clippy -- -D warnings clean, and satisfy cargo deny check per deny.toml.

**/*.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.
For Rust changes headed for review, run cargo fmt --all and cargo clippy --workspace --all-targets -- -D warnings even if relying on pre-commit.

Files:

  • crates/python/src/py_callable.rs
  • crates/core/src/api/llm.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/src/builtin.rs
**/*.{rs,go,js,ts}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding // comment form.

Files:

  • crates/python/src/py_callable.rs
  • crates/core/src/api/llm.rs
  • crates/worker/src/lib.rs
  • crates/pii-redaction/src/builtin.rs
crates/{python,ffi,node}/**/*

⚙️ CodeRabbit configuration file

crates/{python,ffi,node}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.

Files:

  • crates/python/src/py_callable.rs
python/tests/**/*.py

📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)

python/tests/**/*.py: Pytest is used to run tests.
Do not add @pytest.mark.asyncio to any test; async tests are automatically detected and run by the async runner.
Do not add a -> None return type annotation to test functions.
When mocking a class, do not define a new class; use unittest.mock.MagicMock or unittest.mock.AsyncMock, with the spec constructor argument when necessary.
Name mocked classes with the mock prefix, not fake.
Prefer pytest fixtures over helper methods.
Do not repeat fixtures; if a fixture is needed in multiple test files, place it in a conftest.py file.
When creating a fixture, use @pytest.fixture(name="<fixture_name>"[, scope="<scope>"]) and define the fixture function as def <fixture_name>_fixture() -> <return_type>:; only specify scope when it is not function.
Prefer pytest.mark.parametrize over creating individual tests for different input types.

Files:

  • python/tests/plugin/test_worker_sdk.py
{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:

  • python/tests/plugin/test_worker_sdk.py
{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/api/llm.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

Files:

  • crates/core/src/api/llm.rs
crates/core/src/{api/**/*.rs,api/runtime/**/*.rs,codec/**/*.rs,json.rs}

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Implement the new or changed public runtime behavior first in the Rust core, especially under crates/core/src/api/ and related core modules such as crates/core/src/api/runtime/, crates/core/src/codec/, and crates/core/src/json.rs.

Files:

  • crates/core/src/api/llm.rs
crates/{core,adaptive}/**/*

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

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

Files:

  • crates/core/src/api/llm.rs
crates/core/src/api/{tool,llm,shared,scope}.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Wire the new middleware chain into the appropriate lifecycle owner and pipeline stage: tool and LLM execution paths use tool.rs or llm.rs; shared mark and scope event sanitization uses shared.rs and is called from scope.rs.

Files:

  • crates/core/src/api/llm.rs
crates/core/src/api/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Preserve the documented pipeline order: conditional guardrails, request intercepts, request sanitization, execution intercepts, and response sanitization for tool and LLM execution; specialized sanitization, event creation, and dispatch for mark and scope events.

Files:

  • crates/core/src/api/llm.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/api/llm.rs
{crates/core/src/plugin/dynamic/**,crates/plugin/**,crates/worker/**,crates/worker-proto/**,crates/types/**,python/plugin/**,examples/rust-native-plugin/**,examples/python-grpc-worker-plugin/**,docs/build-plugins/**}

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

Keep the stable boundary explicit: native plugins cross a C ABI, and worker plugins cross grpc-v1.

Files:

  • crates/worker/src/lib.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
{crates/worker-proto/**/*.{rs,proto},crates/worker/**/*.rs}

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

Keep worker protocol DTOs in JsonEnvelope; protobuf should own control flow, not duplicated Relay data models.

Files:

  • crates/worker/src/lib.rs
{crates/core/src/plugin/dynamic/**/*.rs,crates/plugin/**/*.rs,crates/worker/**/*.rs,crates/worker-proto/**/*.rs,python/plugin/**/*.py}

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

Manifest validation must cover kind, compatibility, load contract, integrity, capability mismatch, and disabled-plugin behavior.

Files:

  • crates/worker/src/lib.rs
  • python/plugin/src/nemo_relay_plugin/_api.py
crates/worker/**/*.rs

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

Worker activation must cover process launch, token authentication, handshake, validation, declarative registration, proxy rollback, cancellation, and shutdown.

Files:

  • crates/worker/src/lib.rs
{crates/plugin/**/*.rs,python/plugin/**/*.py}

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

Rust and Python SDKs must expose every supported registration surface.

Files:

  • python/plugin/src/nemo_relay_plugin/_api.py
🔇 Additional comments (8)
crates/python/src/py_callable.rs (1)

855-863: 📐 Maintainability & Code Quality

Run the required Rust validation before handoff.

Confirm this source retains its SPDX header, then run cargo fmt --all, cargo clippy --workspace --all-targets -- -D warnings, and just test-rust.

As per coding guidelines, “Any Rust change must run just test-rust”, cargo fmt --all, and cargo clippy --workspace --all-targets -- -D warnings; Rust source files require an SPDX header.

Also applies to: 1074-1110

Source: Coding guidelines

crates/core/src/api/llm.rs (1)

22-22: LGTM!

Also applies to: 733-734, 771-790

crates/worker/src/lib.rs (2)

442-480: 🗄️ Data Integrity & Integration

Verify duplicate registration names cannot overwrite contextual callbacks.

The contextual handler maps use insert(name.into(), ...), while push_contextual_registration records a registration entry separately. Confirm that duplicate names are rejected before insertion; otherwise multiple priority entries can resolve to the last callback stored for that name, breaking duplicate-name and rollback semantics.


138-150: LGTM!

Also applies to: 175-176, 579-585, 1504-1607, 1776-1827, 1879-1885, 1925-1926

python/nemo_relay/guardrails.py (1)

336-408: LGTM! The docstrings for register_contextual_llm_sanitize_request/register_contextual_llm_sanitize_response now include Args/Returns/Notes/Example sections matching their sibling functions, addressing the earlier feedback.

python/plugin/src/nemo_relay_plugin/_api.py (1)

113-121: LGTM! _llm_sanitize_context correctly normalizes empty-string codec names to None, and the contextual dispatch in _invoke_result cleanly separates contextual vs. legacy LLM sanitizer handling, consistent with the cross-language LlmSanitizeContext contract.

Also applies to: 1971-2002, 2084-2089

python/tests/plugin/test_worker_sdk.py (1)

724-777: LGTM! Redundant return None from the prior review is removed, and the added (True, "") case plus its expected entries correctly validate empty-string-to-None codec-name normalization.

crates/pii-redaction/src/builtin.rs (1)

393-458: LGTM! Both previously flagged issues are resolved: the duplicated omission-warning logic is now centralized in log_llm_payload_omitted, and the needless response payload.clone() is gone. The contextual sanitize/omission gating correctly restricts legacy-codec fallback to the no-active-codec case, matching the PR's privacy-safe-omission objective.

@willkill07 willkill07 self-assigned this Jul 23, 2026
@willkill07 willkill07 added this to the 0.7 milestone Jul 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/pii-redaction/src/builtin.rs`:
- Around line 501-551: Update replace_sanitized_json_pointer_value so the
Json::Object branch always returns Some(()) after inserting the replacement,
rather than using Map::insert’s Option result as the success signal. Preserve
the existing array and traversal 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: 387afd46-3d88-4f00-8f6f-70ad5353e247

📥 Commits

Reviewing files that changed from the base of the PR and between d8251ce and 130a283.

📒 Files selected for processing (1)
  • crates/pii-redaction/src/builtin.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 (9)
**/*.rs

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

**/*.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

When changing the core Rust runtime or Rust-facing API surface, format Rust code with cargo fmt (rustfmt defaults), keep cargo clippy -- -D warnings clean, and satisfy cargo deny check per deny.toml.

**/*.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.
For Rust changes headed for review, run cargo fmt --all and cargo clippy --workspace --all-targets -- -D warnings even if relying on pre-commit.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*.{rs,py}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions in Rust and Python: use snake_case.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*.{rs,py,js,mjs,cjs,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{rs,py,js,mjs,cjs,ts,tsx}: 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, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*.{rs,py,go,js,ts,c,h}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use language-appropriate naming conventions: Rust snake_case, C FFI exports prefixed nemo_relay_, Go PascalCase, Node.js camelCase, and Python snake_case.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*.{rs,go,js,ts}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding // comment form.

Files:

  • crates/pii-redaction/src/builtin.rs
{crates/**/src/**/*.rs,python/**/*.py}

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

Do not add tests under src; Rust tests belong in crate tests/ trees, and Python SDK tests belong under python/tests.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*

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

**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, use maintain-dynamic-plugins and include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, prefer uv run pre-commit run --files <changed files...>.
Before review or handoff, run uv run pre-commit run --all-files.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*.{rs,py,go,js,ts}

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

If a language surface changed, always run that language's test target even when Rust core did not change.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*.{rs,py,js,ts,tsx,go,java,kt,swift}

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.

Files:

  • crates/pii-redaction/src/builtin.rs
🔇 Additional comments (5)
crates/pii-redaction/src/builtin.rs (5)

15-23: LGTM!

Also applies to: 35-35, 172-172


288-306: Codec selection correctly prioritizes per-call context over the configured fallback.

selected_surface uses the active codec's surface when context.has_active_codec is true, only falling back to legacy_surface otherwise — matches the mixed-provider + compatibility-fallback requirement from the linked issue.


357-368: LGTM!

Confirms the previously flagged payload.clone() was removed — payload is now moved directly into sanitize_response_with_codec's caller usage without an extra clone.


15-551: 📐 Maintainability & Code Quality

Confirm the Rust validation pipeline was run for this change.

As per coding guidelines, any Rust change to this file must have cargo fmt --all, cargo clippy --workspace --all-targets -- -D warnings, and just test-rust run against it before review/handoff.

Source: Coding guidelines


307-355: 🗄️ Data Integrity & Integration

No issue: target_paths are defined against the normalized LLM payload, so resolving them from AnnotatedLlmRequest is expected.

			> Likely an incorrect or invalid review comment.

Comment thread crates/pii-redaction/src/builtin.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
crates/pii-redaction/src/builtin.rs (2)

318-324: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Make the target-path fallback all-or-nothing
sanitize_request_target_paths_incrementally clones the original request and skips missing paths, so the encode-failure fallback can still return Some(request.clone()) or a partially sanitized request. If any configured target path can’t be replaced and re-encoded, bail out with 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/pii-redaction/src/builtin.rs` around lines 318 - 324, Update
sanitize_request_target_paths_incrementally so it returns None whenever any
configured target path is missing, cannot be replaced, or fails re-encoding; do
not return the cloned original request or a partially sanitized request.
Preserve the existing successful path by returning Some only after every
configured target path has been replaced and the resulting request has been
encoded successfully.

73-175: 📐 Maintainability & Code Quality | 🔵 Trivial

Run the Rust validation suite before handoff.
cargo fmt --all, just test-rust, cargo clippy --workspace --all-targets -- -D warnings, and uv run pre-commit run --all-files.

🤖 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/pii-redaction/src/builtin.rs` around lines 73 - 175, Before handoff,
run the Rust validation commands cargo fmt --all, just test-rust, cargo clippy
--workspace --all-targets -- -D warnings, and uv run pre-commit run --all-files,
resolving any failures they report.

Source: Coding guidelines

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

Outside diff comments:
In `@crates/pii-redaction/src/builtin.rs`:
- Around line 318-324: Update sanitize_request_target_paths_incrementally so it
returns None whenever any configured target path is missing, cannot be replaced,
or fails re-encoding; do not return the cloned original request or a partially
sanitized request. Preserve the existing successful path by returning Some only
after every configured target path has been replaced and the resulting request
has been encoded successfully.
- Around line 73-175: Before handoff, run the Rust validation commands cargo fmt
--all, just test-rust, cargo clippy --workspace --all-targets -- -D warnings,
and uv run pre-commit run --all-files, resolving any failures they report.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: a4a0272e-3960-4254-bb3e-cb8f46365076

📥 Commits

Reviewing files that changed from the base of the PR and between 130a283 and 5a5d99c.

📒 Files selected for processing (1)
  • crates/pii-redaction/src/builtin.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 (9)
**/*.rs

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

**/*.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

When changing the core Rust runtime or Rust-facing API surface, format Rust code with cargo fmt (rustfmt defaults), keep cargo clippy -- -D warnings clean, and satisfy cargo deny check per deny.toml.

**/*.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.
For Rust changes headed for review, run cargo fmt --all and cargo clippy --workspace --all-targets -- -D warnings even if relying on pre-commit.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*.{rs,py}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions in Rust and Python: use snake_case.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*.{rs,py,js,mjs,cjs,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{rs,py,js,mjs,cjs,ts,tsx}: 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, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*.{rs,py,go,js,ts,c,h}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use language-appropriate naming conventions: Rust snake_case, C FFI exports prefixed nemo_relay_, Go PascalCase, Node.js camelCase, and Python snake_case.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*.{rs,go,js,ts}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding // comment form.

Files:

  • crates/pii-redaction/src/builtin.rs
{crates/**/src/**/*.rs,python/**/*.py}

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

Do not add tests under src; Rust tests belong in crate tests/ trees, and Python SDK tests belong under python/tests.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*

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

**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, use maintain-dynamic-plugins and include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, prefer uv run pre-commit run --files <changed files...>.
Before review or handoff, run uv run pre-commit run --all-files.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*.{rs,py,go,js,ts}

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

If a language surface changed, always run that language's test target even when Rust core did not change.

Files:

  • crates/pii-redaction/src/builtin.rs
**/*.{rs,py,js,ts,tsx,go,java,kt,swift}

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.

Files:

  • crates/pii-redaction/src/builtin.rs
🔇 Additional comments (3)
crates/pii-redaction/src/builtin.rs (3)

15-23: LGTM!

Also applies to: 35-35, 162-167, 172-172


541-544: LGTM!


357-367: 🔒 Security & Privacy

No action needed: the codec-specific overlay helpers remove omitted fields from the returned JSON, and decode/sanitize failures still short-circuit to None.

			> Likely an incorrect or invalid review comment.

@willkill07 willkill07 changed the title fix: sanitize PII with active LLM codec feat(sanitizers)!: unify LLM sanitizer callbacks Jul 23, 2026
@github-actions github-actions Bot added Feature a new feature breaking PR introduces a breaking change and removed Bug issue describes bug; PR fixes bug labels Jul 23, 2026
@willkill07 willkill07 changed the title feat(sanitizers)!: unify LLM sanitizer callbacks feat(sanitizers)!: make LLM sanitizers codec-aware Jul 24, 2026
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
Signed-off-by: Will Killian <wkillian@nvidia.com>
@willkill07
willkill07 force-pushed the fix/per-call-codec-aware-pii-sanitization branch from 3bff175 to abfaa44 Compare July 26, 2026 16:45
@willkill07 willkill07 changed the title feat(sanitizers)!: make sanitizers async and expose per-call codecs feat(sanitizers)!: expose per-call codec capabilities Jul 26, 2026
@willkill07

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Signed-off-by: Will Killian <wkillian@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 17

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
crates/core/src/api/runtime/state.rs (1)

959-977: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Both LLM sanitize snapshot chains kept their pre-refactor doc blocks and loop shape. The Option-returning contextual refactor changed the signature and the return contract of both functions, but neither doc block mentions the context parameter or the omission semantics, and both loops keep iterating after value becomes None.

  • crates/core/src/api/runtime/state.rs#L959-L977: document context and the None-omits-payload-and-annotation return, and replace the and_then accumulation with (entry.payload)(value, context.clone())? so the short-circuit is explicit.
  • crates/core/src/api/runtime/state.rs#L998-L1016: apply the identical doc and loop fix to llm_sanitize_response_snapshot_chain.
🤖 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/runtime/state.rs` around lines 959 - 977, Update both
llm_sanitize_request_snapshot_chain
(crates/core/src/api/runtime/state.rs:959-977) and
llm_sanitize_response_snapshot_chain
(crates/core/src/api/runtime/state.rs:998-1016) to document the context
parameter and that None omits the payload and annotation. Replace each and_then
accumulation loop with explicit ?-based short-circuiting so iteration stops
immediately when a sanitizer returns None.
crates/pii-redaction/src/component.rs (1)

1111-1129: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Unsupported codec values are silently accepted when both LLM surfaces are off.

With input = false and output = false (still a valid config when tool/mark surfaces are enabled), the early return at Line 1113 skips the supported-name check entirely, so codec = "bogus" validates clean. Now that codec is purely a fallback, gate the name check on codec.is_some() rather than on surface enablement — the value is malformed regardless of which surfaces consume it.

🛡️ Proposed fix
-    let llm_surface_enabled = config.input || config.output;
-    if !llm_surface_enabled {
-        return;
-    }
-
     let Some(codec) = config.codec.as_deref() else {
         return;
     };
🤖 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/pii-redaction/src/component.rs` around lines 1111 - 1129, Update the
codec validation flow around llm_surface_enabled so supported_codec_names() is
checked whenever config.codec is present, even when both input and output are
disabled. Keep the early return only for cases with no enabled LLM surfaces, and
preserve the existing diagnostic for unsupported codec values.
go/nemo_relay/guardrails/guardrails_test.go (1)

122-145: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Discarded unmarshal errors turn a payload regression into a nil-map panic.

_ = json.Unmarshal(...) leaves payload nil when request.Content / response is empty or malformed, and the next line writes into it — panicking instead of failing with a usable message. If the DTO plumbing ever stops populating Content, this test crashes opaquely.

🛡️ Proposed fix
 		func(request nemo_relay.LLMRequestDTO, _ nemo_relay.LLMSanitizeRequestContext) (nemo_relay.LLMRequestDTO, bool) {
 			var payload map[string]interface{}
-			_ = json.Unmarshal(request.Content, &payload)
+			if err := json.Unmarshal(request.Content, &payload); err != nil || payload == nil {
+				t.Fatalf("unmarshal request content: %v (raw=%s)", err, request.Content)
+			}
 			payload["request_sanitized"] = true

Same for the response callback at Lines 139-144.

🤖 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 `@go/nemo_relay/guardrails/guardrails_test.go` around lines 122 - 145, Handle
json.Unmarshal errors in both the callbacks registered by
RegisterLlmSanitizeRequest and RegisterLlmSanitizeResponse before writing to the
decoded payload map. Fail the test with a clear message that identifies whether
request.Content or the response payload was invalid, and only mutate and marshal
the map after successful decoding.
🤖 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/runtime/callbacks.rs`:
- Around line 186-229: Update LlmSanitizeRequestContext and
LlmSanitizeResponseContext so codec identity is read through a codec() accessor
rather than a publicly writable field, while preserving their existing
constructors and resolve_codec() behavior. Document that identity-only contexts
may report a non-None codec identity while resolve_codec() returns None, and
sanitizers must handle that state without unwrapping the handle; keep identity
and handle updates synchronized through controlled construction.

In `@crates/core/src/plugin/dynamic/native.rs`:
- Around line 1947-1960: Reorder the native codec identity allocation in the
request flow so `native_llm_codec_identity` runs only after request
serialization and `native_string_from_json` have succeeded, preventing
`context_id` leaks on early returns. Apply the same ordering in
`call_llm_sanitize_response_callback`, keeping the resulting codec identity and
context construction unchanged.

In `@crates/core/tests/fixtures/worker_plugin/src/main.rs`:
- Around line 67-70: Run cargo fmt --all to reformat the
register_mark_sanitize_guardrail invocation in the worker plugin fixture,
wrapping the closure declaration to comply with rustfmt’s default line width
while preserving its behavior.

In `@crates/core/tests/unit/llm_api_tests.rs`:
- Around line 136-161: Add response-side coverage for the runtime codec identity
in the sanitize_context_for_response_codec tests, using a RuntimeIdentityCodec
configured with “com.example.chat.v1” and asserting the resulting
LlmCodecIdentity::Runtime value. Update the test fixture or implementation as
needed so RuntimeIdentityCodec supports the response codec path while preserving
the existing built-in, None, and Opaque assertions.

In `@crates/ffi/src/api/llm.rs`:
- Around line 56-59: Update the documentation for the encode helper returning
*mut FfiLLMRequest to state its ownership contract: returning it from the
sanitizer transfers ownership to Relay, while otherwise the caller must
explicitly free it. Regenerate the generated nemo_relay.h through the proper
build step so the C-facing documentation includes this contract.

In `@crates/pii-redaction/src/builtin.rs`:
- Around line 545-555: The request and response omission paths should
distinguish unavailable projection inputs from codec operation failures. In the
request callback, use a no-codec reason when `codec` is `None`, and retain the
existing codec failure reason only when sanitization was attempted; apply the
same split in the response callback around `surface.zip(codec)`, using a reason
such as “no built-in response projection for active codec” when unavailable and
preserving the codec failure reason for attempted operations.

In `@crates/pii-redaction/tests/unit/component_tests.rs`:
- Around line 4088-4110: Convert the four affected tests, including
builtin_backend_removes_targeted_message_names_and_ignores_missing_normalized_paths,
from synchronous #[test] functions to #[tokio::test] async functions. Replace
each futures::executor::block_on(initialize_plugins(...)) call with a direct
awaited initialize_plugins call, preserving the existing mutex, setup,
configuration, and assertions.

In `@crates/python/src/py_callable.rs`:
- Around line 56-74: Add a coverage test for
validate_python_llm_sanitizer_signature that supplies a legacy single-argument
callable, asserts validation fails with PyTypeError, and verifies the rejection
message identifies the required `(payload, context)` signature. Keep existing
tests for valid two-argument callbacks unchanged.

In `@crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto`:
- Around line 57-62: Rename the zero value in enum LlmCodecKind from
LLM_CODEC_KIND_NONE to LLM_CODEC_KIND_UNSPECIFIED, preserving its numeric value
of 0 and leaving the other enum members unchanged.

In `@crates/worker/src/lib.rs`:
- Around line 1650-1658: Merge the separate RegistrationSurface match arms in
the tool-response dispatch so ToolSanitizeRequestGuardrail is grouped with
ToolSanitizeResponseGuardrail, ToolConditionalExecutionGuardrail,
ToolRequestIntercept, and ToolExecutionIntercept. Preserve the shared
invoke_tool_response(request, &scope, surface).await behavior.
- Around line 686-752: Update decode_llm_codec_request,
encode_llm_codec_request, and decode_llm_codec_response to use the shared schema
identifier constants instead of duplicated string literals. Route codec
capability identity through the codec’s id() source rather than manually passing
or reconstructing names, preserving the existing request/response behavior and
preventing opaque codec identities.

In `@crates/worker/tests/worker_sdk_tests.rs`:
- Around line 694-718: Capture both results returned by invoke_json for the
codec request and response in the relevant worker SDK test, then use
assert_json_field to verify each contains the mock’s distinguishable payload,
{"headers": {}, "content": {}}. Keep the existing sanitizer setup and host-call
assertions unchanged while asserting the WorkerRequestCodec::encode and
WorkerResponseCodec::decode results reach sanitizer output.

In `@docs/configure-plugins/pii-redaction/configuration.mdx`:
- Around line 93-122: Add a concise sentence to the “Mixed-Provider Gateway
Example” explaining that manual managed calls without an active codec are
omitted when codec is not configured, including their LLM payload and
annotation; direct readers to configure the legacy codec fallback for such calls
while preserving the existing managed-call behavior.

In `@docs/reference/llm-request-intercept-outcomes.mdx`:
- Around line 92-98: Add the Go binding to the contract list in the documented
callback outcomes section, naming its exposed symbols LLMRequestInterceptOutcome
and LlmRequestIntercepts. Keep the existing Python, Rust, Node.js, and C
callback descriptions unchanged.

In `@go/nemo_relay/llm_test.go`:
- Around line 338-351: Update the response callback in the codec test to assert
the resolved codec identity before decoding: verify its codec kind is
LLMCodecBuiltin and its codec ID is openai_chat, matching the NewOpenAIChatCodec
response configuration and the request callback’s parity checks. Preserve the
existing error recording and decode validation.
- Around line 293-296: Protect all callback-shared state with the existing
stateMu: lock around assignments to requestResolved, responseResolved,
retainedRequestCodec, retainedResponseCodec, and retainedRequest in both
sanitizer callbacks, then lock around their reads after LlmCallExecute returns.
Match the existing callbackErrorsMu synchronization pattern without changing the
callback behavior.

In `@python/tests/plugin/test_worker_sdk.py`:
- Around line 940-960: Update the nested request_sanitizer and
response_sanitizer callbacks in CodecFailurePlugin.register with the same
parameter and return-type annotations used by the equivalent sanitizer callbacks
elsewhere in the file, preserving their existing behavior.

---

Outside diff comments:
In `@crates/core/src/api/runtime/state.rs`:
- Around line 959-977: Update both llm_sanitize_request_snapshot_chain
(crates/core/src/api/runtime/state.rs:959-977) and
llm_sanitize_response_snapshot_chain
(crates/core/src/api/runtime/state.rs:998-1016) to document the context
parameter and that None omits the payload and annotation. Replace each and_then
accumulation loop with explicit ?-based short-circuiting so iteration stops
immediately when a sanitizer returns None.

In `@crates/pii-redaction/src/component.rs`:
- Around line 1111-1129: Update the codec validation flow around
llm_surface_enabled so supported_codec_names() is checked whenever config.codec
is present, even when both input and output are disabled. Keep the early return
only for cases with no enabled LLM surfaces, and preserve the existing
diagnostic for unsupported codec values.

In `@go/nemo_relay/guardrails/guardrails_test.go`:
- Around line 122-145: Handle json.Unmarshal errors in both the callbacks
registered by RegisterLlmSanitizeRequest and RegisterLlmSanitizeResponse before
writing to the decoded payload map. Fail the test with a clear message that
identifies whether request.Content or the response payload was invalid, and only
mutate and marshal the map after successful decoding.
🪄 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: c695a32a-8695-4c96-b234-ffbad1d8bc39

📥 Commits

Reviewing files that changed from the base of the PR and between 3bff175 and abfaa44.

📒 Files selected for processing (95)
  • crates/cli/src/gateway/mod.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/codec/anthropic.rs
  • crates/core/src/codec/openai_chat.rs
  • crates/core/src/codec/openai_responses.rs
  • crates/core/src/codec/traits.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/src/stream.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/integration/api_surface_tests.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/tests/integration/pipeline_tests.rs
  • crates/core/tests/unit/context_tests.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/tests/unit/llm_api_tests.rs
  • crates/core/tests/unit/native_plugin_tests.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/ffi/nemo_relay.h
  • crates/ffi/src/api/llm.rs
  • crates/ffi/src/api/llm_registry.rs
  • crates/ffi/src/api/mod.rs
  • crates/ffi/src/api/plugin.rs
  • crates/ffi/src/api/scope_registry.rs
  • crates/ffi/src/callable.rs
  • crates/ffi/src/types/mod.rs
  • crates/ffi/tests/integration/api_tests.rs
  • crates/ffi/tests/integration/callable_extra_tests.rs
  • crates/ffi/tests/unit/api_tests.rs
  • crates/ffi/tests/unit/callable_tests.rs
  • crates/node/package.json
  • crates/node/plugin.d.ts
  • crates/node/src/api/mod.rs
  • crates/node/src/callable.rs
  • crates/node/src/stream.rs
  • crates/node/tests/callback_error_tests.mjs
  • crates/node/tests/event_sanitizers_tests.mjs
  • crates/node/tests/llm_tests.mjs
  • crates/pii-redaction/README.md
  • crates/pii-redaction/src/builtin.rs
  • crates/pii-redaction/src/component.rs
  • crates/pii-redaction/src/overlay.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/python/src/py_api/mod.rs
  • crates/python/src/py_callable.rs
  • crates/python/src/py_plugin.rs
  • crates/python/src/py_types/codecs.rs
  • crates/python/src/py_types/core.rs
  • crates/python/src/py_types/mod.rs
  • crates/python/tests/coverage/coverage_tests.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/python/tests/coverage/py_callable_coverage_tests.rs
  • crates/python/tests/coverage/py_plugin_coverage_tests.rs
  • crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto
  • crates/worker/src/lib.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • docs/about-nemo-relay/concepts/middleware.mdx
  • docs/about-nemo-relay/release-notes/index.mdx
  • docs/build-plugins/dynamic-plugins/about.mdx
  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • docs/build-plugins/dynamic-plugins/native-dynamic/about.mdx
  • docs/build-plugins/language-binding/about.mdx
  • docs/configure-plugins/pii-redaction/about.mdx
  • docs/configure-plugins/pii-redaction/configuration.mdx
  • docs/reference/llm-request-intercept-outcomes.mdx
  • docs/reference/migration-guides.mdx
  • examples/rust-native-plugin/src/lib.rs
  • go/nemo_relay/adaptive_plugin_test.go
  • go/nemo_relay/callbacks.go
  • go/nemo_relay/callbacks_test.go
  • go/nemo_relay/deregister_test.go
  • go/nemo_relay/error_test.go
  • go/nemo_relay/guardrails/guardrails_test.go
  • go/nemo_relay/llm_test.go
  • go/nemo_relay/nemo_relay.go
  • go/nemo_relay/plugin.go
  • go/nemo_relay/scope_local_test.go
  • python/nemo_relay/__init__.py
  • python/nemo_relay/__init__.pyi
  • python/nemo_relay/_native.pyi
  • python/nemo_relay/guardrails.py
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • python/plugin/src/nemo_relay_plugin/_api.py
  • python/tests/plugin/test_worker_sdk.py
  • python/tests/test_builtin_codecs.py
  • python/tests/test_llm.py
  • python/tests/test_scope_local.py
💤 Files with no reviewable changes (1)
  • crates/pii-redaction/README.md

Comment thread crates/core/src/api/runtime/callbacks.rs
Comment thread crates/core/src/plugin/dynamic/native.rs Outdated
Comment thread crates/core/tests/fixtures/worker_plugin/src/main.rs Outdated
Comment thread crates/core/tests/unit/llm_api_tests.rs
Comment thread crates/ffi/src/api/llm.rs
Comment thread docs/configure-plugins/pii-redaction/configuration.mdx
Comment thread docs/reference/llm-request-intercept-outcomes.mdx
Comment thread go/nemo_relay/llm_test.go Outdated
Comment thread go/nemo_relay/llm_test.go
Comment thread python/tests/plugin/test_worker_sdk.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/worker/tests/worker_sdk_tests.rs (1)

1846-1880: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Add codec error-path assertions.

The LLM sanitize callbacks use ? on codec decode/encode, but this test only exercises success and Ok(None). Add cases where decode and encode fail and assert the guardrail returns an error instead of forwarding the unsanitized payload.

🤖 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/worker/tests/worker_sdk_tests.rs` around lines 1846 - 1880, Add
error-path cases to the guardrail tests around the LLM sanitize callbacks:
configure a codec whose decode fails and assert both request and response
guardrails return an error, then configure encode to fail and assert the request
guardrail also returns an error. Verify failed operations do not forward the
original or unsanitized payload, while preserving the existing success and
Ok(None) cases.

Source: Path instructions

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

Outside diff comments:
In `@crates/worker/tests/worker_sdk_tests.rs`:
- Around line 1846-1880: Add error-path cases to the guardrail tests around the
LLM sanitize callbacks: configure a codec whose decode fails and assert both
request and response guardrails return an error, then configure encode to fail
and assert the request guardrail also returns an error. Verify failed operations
do not forward the original or unsanitized payload, while preserving the
existing success and Ok(None) cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 1797ed78-6ef5-4029-accf-4e0bb9cfff90

📥 Commits

Reviewing files that changed from the base of the PR and between abfaa44 and 744c4ae.

📒 Files selected for processing (1)
  • crates/worker/tests/worker_sdk_tests.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Check / Run
🧰 Additional context used
📓 Path-based instructions (13)
**/*.rs

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

**/*.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

When changing the core Rust runtime or Rust-facing API surface, format Rust code with cargo fmt (rustfmt defaults), keep cargo clippy -- -D warnings clean, and satisfy cargo deny check per deny.toml.

**/*.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.
For Rust changes headed for review, run cargo fmt --all and cargo clippy --workspace --all-targets -- -D warnings even if relying on pre-commit.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
**/*.{rs,py}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions in Rust and Python: use snake_case.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
**/*.{rs,py,js,mjs,cjs,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{rs,py,js,mjs,cjs,ts,tsx}: 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, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
**/*.{rs,py,go,js,ts,c,h}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use language-appropriate naming conventions: Rust snake_case, C FFI exports prefixed nemo_relay_, Go PascalCase, Node.js camelCase, and Python snake_case.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
**/*.{rs,go,js,ts}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding // comment form.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
{crates/core/src/plugin/dynamic/**,crates/plugin/**,crates/worker/**,crates/worker-proto/**,crates/types/**,python/plugin/**,examples/rust-native-plugin/**,examples/python-grpc-worker-plugin/**,docs/build-plugins/**}

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

Keep the stable boundary explicit: native plugins cross a C ABI, and worker plugins cross grpc-v1.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
{crates/worker-proto/**/*.{rs,proto},crates/worker/**/*.rs}

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

Keep worker protocol DTOs in JsonEnvelope; protobuf should own control flow, not duplicated Relay data models.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
{crates/core/src/plugin/dynamic/**/*.rs,crates/plugin/**/*.rs,crates/worker/**/*.rs,crates/worker-proto/**/*.rs,python/plugin/**/*.py}

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

Manifest validation must cover kind, compatibility, load contract, integrity, capability mismatch, and disabled-plugin behavior.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
crates/worker/**/*.rs

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

Worker activation must cover process launch, token authentication, handshake, validation, declarative registration, proxy rollback, cancellation, and shutdown.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
**/*

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

**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, use maintain-dynamic-plugins and include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, prefer uv run pre-commit run --files <changed files...>.
Before review or handoff, run uv run pre-commit run --all-files.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
**/*.{rs,py,go,js,ts}

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

If a language surface changed, always run that language's test target even when Rust core did not change.

Files:

  • crates/worker/tests/worker_sdk_tests.rs
**/*.{rs,py,js,ts,tsx,go,java,kt,swift}

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.

Files:

  • crates/worker/tests/worker_sdk_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/worker/tests/worker_sdk_tests.rs
🔇 Additional comments (2)
crates/worker/tests/worker_sdk_tests.rs (2)

203-218: Run the required Rust validation before handoff.

Please run cargo fmt --all, just test-rust, cargo clippy --workspace --all-targets -- -D warnings, and uv run pre-commit run --all-files for this Rust change.

Source: Coding guidelines


502-515: LGTM!

Also applies to: 663-686, 687-733, 820-822, 1594-1595, 1739-1765, 2207-2263, 2519-2519, 2543-2543

Signed-off-by: Will Killian <wkillian@nvidia.com>

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

afourniernv added a commit to afourniernv/NeMo-Flow that referenced this pull request Jul 26, 2026
Signed-off-by: Alex Fournier <afournier@nvidia.com>
@willkill07

Copy link
Copy Markdown
Member Author

/merge

@rapids-bot
rapids-bot Bot merged commit 42c7655 into NVIDIA:main Jul 26, 2026
69 checks passed
@willkill07
willkill07 deleted the fix/per-call-codec-aware-pii-sanitization branch July 26, 2026 22:58
afourniernv added a commit to afourniernv/NeMo-Flow that referenced this pull request Jul 26, 2026
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

breaking PR introduces a breaking change Feature a new feature lang:go PR changes/introduces Go code lang:js PR changes/introduces Javascript/Typescript code lang:python PR changes/introduces Python code lang:rust PR changes/introduces Rust code size:XXL PR is very large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement]: Make PII redaction use the active per-call provider codec

3 participants