feat(plugin)!: support pending marks from LLM intercepts#327
Conversation
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
|
Caution Review failedAn error occurred during the review process. Please try again later. WalkthroughIntroduces ChangesLLM Request Intercept Pending Marks
Estimated code review effort: 4 (Complex) | ~75 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant llm_call_execute
participant run_request_intercepts_with_codec
participant llm_request_intercepts_snapshot_chain
participant emit_llm_start
participant emit_pending_request_marks
Client->>llm_call_execute: invoke LLM call
llm_call_execute->>run_request_intercepts_with_codec: run intercept chain
run_request_intercepts_with_codec->>llm_request_intercepts_snapshot_chain: execute registered intercepts
llm_request_intercepts_snapshot_chain-->>run_request_intercepts_with_codec: LlmRequestInterceptOutcome (request, annotated, pending_marks)
run_request_intercepts_with_codec-->>llm_call_execute: request, annotated_request, pending_marks
llm_call_execute->>emit_llm_start: emit LLM start event
llm_call_execute->>emit_pending_request_marks: emit pending marks after start
llm_call_execute->>Client: provider execution result
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 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/tests/unit/shared_tests.rs (1)
196-221: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winAdd a positive pending-mark case for the codec branch.
This only checks that the new third return value is empty. The codec path is the branch that changed, and a regression that drops
pending_marksaftercodec.encodewould still pass here. Add one intercept that returns a realPendingMarkSpecand assert it survives theSome(codec)path.Suggested test shape
- register_llm_request_intercept( + register_llm_request_intercept_with_marks( "shared-codec", 1, false, Arc::new(|_name, mut request, annotated| { let mut annotated = annotated.expect("codec should provide annotated request"); annotated.model = Some("intercepted-model".into()); request.headers.insert("x-codec".into(), json!(true)); - Ok((request, Some(annotated))) + Ok( + LlmRequestInterceptOutcome::new(request, Some(annotated)) + .with_pending_mark(PendingMarkSpec::builder().name("codec.mark").build()), + ) }), ) .unwrap(); @@ - assert!(pending_marks_with_codec.is_empty()); + assert_eq!(pending_marks_with_codec.len(), 1); + assert_eq!(pending_marks_with_codec[0].name, "codec.mark");As per path instructions, "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."
🤖 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/tests/unit/shared_tests.rs` around lines 196 - 221, Add a positive assertion for the codec branch in shared_tests by exercising run_request_intercepts_with_codec with an interceptor that returns a real PendingMarkSpec, then verify pending_marks_with_codec still contains that mark after codec.encode runs. Keep the existing assertions on request_with_codec and annotated_with_codec, but replace the shallow is_empty check with a check that the pending mark survives the Some(codec) path so the regression around dropping pending_marks is covered.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.
Inline comments:
In `@crates/core/src/api/shared.rs`:
- Around line 107-113: The fallback branch in the request encoding flow drops
LlmRequestInterceptOutcome.annotated_request whenever no codec is configured,
which loses interceptor-produced annotations. Update the matching logic around
the codec/annotated_request handling so the branch in shared response building
preserves and returns the annotated_request even when codec is None, using the
existing codec/encode path and outcome.request tuple assembly as the place to
adjust.
In `@crates/core/src/plugin/dynamic/native.rs`:
- Around line 1788-1794: The NativeLlmRequestInterceptOutcome deserialization is
too strict for pending_marks, causing empty marked outcomes from
LlmRequestInterceptOutcome to fail. Update NativeLlmRequestInterceptOutcome to
default pending_marks when omitted, alongside the existing annotated_request
handling, so the native intercept outcome can deserialize the empty form safely.
In `@crates/core/tests/integration/native_plugin_tests.rs`:
- Around line 421-427: The stream test currently checks only that
fixture.native.llm_request.mark is parented to native-fixture-llm-stream, which
can miss incorrect emission order. In
native_plugin_tests::llm_stream_call_execute, add the same timestamp comparison
used in the non-stream path by capturing the ScopeCategory::Start event for
native-fixture-llm-stream and asserting the mark event occurs after that start
event, not just that it shares the start UUID. Keep the existing parent_uuid
assertion and extend it with the ordering check so the test covers lifecycle
sequencing as well as attachment.
In `@crates/plugin/tests/typed_callbacks.rs`:
- Around line 4396-4446: The trampoline test for
register_llm_request_intercept_with_marks only covers a null annotated request,
so it misses the envelope path where an existing AnnotatedLlmRequest could be
dropped. Update the test to pass a non-null annotation through the registration
callback and verify the resulting metadata from the LlmRequestInterceptOutcome
path preserves it under metadata["annotated_request"], while still checking the
pending mark and rewritten request behavior.
In `@crates/types/tests/serialization_tests.rs`:
- Around line 82-113: The serialization test for LlmRequestInterceptOutcome only
covers the case where pending_marks is present; add a backward-compatibility
assertion in llm_request_intercept_outcome_round_trips_pending_marks that
deserializing JSON without pending_marks still succeeds and yields an empty
pending_marks vector. Reuse the existing LlmRequestInterceptOutcome serde
round-trip setup in crates/types/tests/serialization_tests.rs to verify the
omitted-field decode path explicitly.
---
Outside diff comments:
In `@crates/core/tests/unit/shared_tests.rs`:
- Around line 196-221: Add a positive assertion for the codec branch in
shared_tests by exercising run_request_intercepts_with_codec with an interceptor
that returns a real PendingMarkSpec, then verify pending_marks_with_codec still
contains that mark after codec.encode runs. Keep the existing assertions on
request_with_codec and annotated_with_codec, but replace the shallow is_empty
check with a check that the pending mark survives the Some(codec) path so the
regression around dropping pending_marks is covered.
🪄 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: 182915b6-f580-4ff4-b702-8f61bf5d9a0a
📒 Files selected for processing (20)
crates/core/src/api/llm.rscrates/core/src/api/registry.rscrates/core/src/api/runtime.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/api/runtime/state.rscrates/core/src/api/shared.rscrates/core/src/context/registries.rscrates/core/src/plugin.rscrates/core/src/plugin/dynamic/native.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/tests/integration/middleware_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/tests/unit/shared_tests.rscrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rscrates/types/src/api/event.rscrates/types/src/api/llm.rscrates/types/tests/serialization_tests.rsexamples/rust-native-plugin/README.mdexamples/rust-native-plugin/src/lib.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 (31)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/core/tests/unit/shared_tests.rscrates/core/src/context/registries.rsexamples/rust-native-plugin/src/lib.rscrates/core/src/api/shared.rscrates/core/src/plugin.rscrates/types/src/api/event.rscrates/core/src/api/runtime/callbacks.rscrates/plugin/tests/typed_callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/runtime.rscrates/types/tests/serialization_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/plugin/src/lib.rscrates/core/tests/integration/middleware_tests.rscrates/types/src/api/llm.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
crates/core/tests/unit/shared_tests.rscrates/types/tests/serialization_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/tests/integration/middleware_tests.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/core/tests/unit/shared_tests.rscrates/core/src/context/registries.rsexamples/rust-native-plugin/src/lib.rscrates/core/src/api/shared.rscrates/core/src/plugin.rscrates/types/src/api/event.rscrates/core/src/api/runtime/callbacks.rscrates/plugin/tests/typed_callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/runtime.rscrates/types/tests/serialization_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/plugin/src/lib.rscrates/core/tests/integration/middleware_tests.rscrates/types/src/api/llm.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/core/tests/unit/shared_tests.rscrates/core/src/context/registries.rsexamples/rust-native-plugin/src/lib.rscrates/core/src/api/shared.rscrates/core/src/plugin.rscrates/types/src/api/event.rscrates/core/src/api/runtime/callbacks.rscrates/plugin/tests/typed_callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/runtime.rscrates/types/tests/serialization_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/plugin/src/lib.rscrates/core/tests/integration/middleware_tests.rscrates/types/src/api/llm.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/core/tests/unit/shared_tests.rscrates/core/src/context/registries.rscrates/core/src/api/shared.rscrates/core/src/plugin.rscrates/core/src/api/runtime/callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/runtime.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/core/tests/unit/shared_tests.rscrates/core/src/context/registries.rsexamples/rust-native-plugin/src/lib.rscrates/core/src/api/shared.rscrates/core/src/plugin.rscrates/types/src/api/event.rscrates/core/src/api/runtime/callbacks.rscrates/plugin/tests/typed_callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/runtime.rscrates/types/tests/serialization_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/plugin/src/lib.rscrates/core/tests/integration/middleware_tests.rscrates/types/src/api/llm.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rs
crates/core/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
If the change touched
crates/coreor shared runtime semantics, also usevalidate-changefor broader validation
crates/core/**/*.rs: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/tests/unit/shared_tests.rscrates/core/src/context/registries.rscrates/core/src/api/shared.rscrates/core/src/plugin.rscrates/core/src/api/runtime/callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/runtime.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rs
crates/{core,adaptive}/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly
Files:
crates/core/tests/unit/shared_tests.rscrates/core/src/context/registries.rscrates/core/src/api/shared.rscrates/core/src/plugin.rscrates/core/src/api/runtime/callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/runtime.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/core/tests/unit/shared_tests.rscrates/core/src/context/registries.rsexamples/rust-native-plugin/src/lib.rscrates/core/src/api/shared.rsexamples/rust-native-plugin/README.mdcrates/core/src/plugin.rscrates/types/src/api/event.rscrates/core/src/api/runtime/callbacks.rscrates/plugin/tests/typed_callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/runtime.rscrates/types/tests/serialization_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/plugin/src/lib.rscrates/core/tests/integration/middleware_tests.rscrates/types/src/api/llm.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/core/tests/unit/shared_tests.rscrates/core/src/context/registries.rsexamples/rust-native-plugin/src/lib.rscrates/core/src/api/shared.rscrates/core/src/plugin.rscrates/types/src/api/event.rscrates/core/src/api/runtime/callbacks.rscrates/plugin/tests/typed_callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/runtime.rscrates/types/tests/serialization_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/plugin/src/lib.rscrates/core/tests/integration/middleware_tests.rscrates/types/src/api/llm.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/core/tests/unit/shared_tests.rscrates/core/src/context/registries.rscrates/core/src/api/shared.rscrates/core/src/plugin.rscrates/types/src/api/event.rscrates/core/src/api/runtime/callbacks.rscrates/plugin/tests/typed_callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/runtime.rscrates/types/tests/serialization_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/plugin/src/lib.rscrates/core/tests/integration/middleware_tests.rscrates/types/src/api/llm.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rs
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # P...
Files:
crates/core/tests/unit/shared_tests.rscrates/core/src/context/registries.rsexamples/rust-native-plugin/src/lib.rscrates/core/src/api/shared.rsexamples/rust-native-plugin/README.mdcrates/core/src/plugin.rscrates/types/src/api/event.rscrates/core/src/api/runtime/callbacks.rscrates/plugin/tests/typed_callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/runtime.rscrates/types/tests/serialization_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/plugin/src/lib.rscrates/core/tests/integration/middleware_tests.rscrates/types/src/api/llm.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.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/shared_tests.rscrates/core/src/context/registries.rscrates/core/src/api/shared.rscrates/core/src/plugin.rscrates/core/src/api/runtime/callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/core/src/api/runtime.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/tests/integration/middleware_tests.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rscrates/core/src/plugin/dynamic/native.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/core/tests/unit/shared_tests.rscrates/plugin/tests/typed_callbacks.rscrates/core/tests/fixtures/native_plugin/src/lib.rscrates/types/tests/serialization_tests.rscrates/core/tests/integration/native_plugin_tests.rscrates/core/tests/integration/middleware_tests.rs
{docs/**,examples/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify examples still run with documented commands for large or public-facing changes
Files:
examples/rust-native-plugin/src/lib.rsexamples/rust-native-plugin/README.md
crates/core/src/api/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Implement behavior first in Rust core API modules:
crates/core/src/api/and related core modules such ascrates/core/src/api/runtime/,crates/core/src/codec/, orcrates/core/src/json.rs
Files:
crates/core/src/api/shared.rscrates/core/src/api/runtime/callbacks.rscrates/core/src/api/runtime.rscrates/core/src/api/runtime/state.rscrates/core/src/api/registry.rscrates/core/src/api/llm.rs
**/*.{md,rst,html,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
**/*.{md,rst,html,txt}: Always spellNVIDIAin all caps. Do not useNvidia,nvidia,nVidia,nVIDIA, orNV.
Usean NVIDIAbefore a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol afterNVIDIAwhen referring to the company.
Use trademark symbols with product names only when the document type or legal guidance requires them.
Verify official capitalization, spacing, and hyphenation for product names.
Precede NVIDIA product names withNVIDIAon first mention when it is natural and accurate.
Do not rewrite product names for grammar or title-case rules.
Preserve third-party product names according to the owner's spelling.
Include the company name and full model qualifier on first use when it helps identify the model.
Preserve the official capitalization and punctuation of model names.
Use shorter family names only after the full name is established.
Spell out a term on first use and put the acronym in parentheses unless the acronym is widely understood by the intended audience.
Use the acronym on later mentions after it has been defined.
For long documents, reintroduce the full term if readers might lose context.
Form plurals of acronyms withs, not an apostrophe, such asGPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such asCPU,GPU,PC,API, andUIusually do not need to be spelled out for developer audiences.
Files:
examples/rust-native-plugin/README.md
**/*.{md,rst,html}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
Link the first mention of a product name when the destination helps the reader.
Files:
examples/rust-native-plugin/README.md
**/*.md
📄 CodeRabbit inference engine (.agents/skills/contribute-integration/SKILL.md)
Documentation must be updated if activation or usage changed
**/*.md: Use title case consistently in technical documentation headings
Avoid quotation marks, ampersands, and exclamation marks in headings
Keep product, event, research, and whitepaper names in their official title case
Use title case for table headers
Do not force social-media sentence case into technical docs
Format code elements, commands, parameters, package names, and expressions in monospace
Format directories, file names, and paths in monospace using backticks
Use angle brackets inside monospace for variables inside paths, such as/home/<username>/.login
Format error messages and strings in quotation marks, keeping literal code strings in code formatting when clearer
Format UI buttons, menus, fields, and labels in bold
Use angle brackets between UI labels for menu paths, such as File > Save As
Use italics for new terms on first use, sparingly and only when introducing the term
Use italics for publication titles
Format keyboard shortcuts in plain text, such as Press Ctrl+Alt+Delete
Use owner/repo link text for GitHub repositories, preferring[NVIDIA/NeMo](link)over prose references like 'the GitHub repo'
Introduce every code block with a complete sentence
Do not make a code block complete the grammar of the previous sentence
Do not continue a sentence after a code block
Use syntax highlighting when the format supports it for code blocks
Avoid the word 'snippet' unless the surrounding docs already use it as a term of art
Keep inline method, function, and class references consistent with nearby docs, omitting empty parentheses for prose readability when no call is shown
Use descriptive anchor text that matches the destination title when possible for links
Avoid raw URLs in running text
Avoid generic anchor text such as 'here,' 'this page,' and 'read more'
Include acronyms in link text when a linked term includes an acronym
Do not link long sentences or multiple sentences
Avoid links ...
Files:
examples/rust-native-plugin/README.md
**/{docs,examples,**/*.md,*.patch,*.diff,.github,*.sh,*.yaml,*.yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update documentation, examples, CI configuration, and patch artifacts when performing rename operations
Files:
examples/rust-native-plugin/README.md
**/*.{md,rst,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
Spell
NVIDIAin all caps. Do not useNvidia,nvidia, orNV.
Files:
examples/rust-native-plugin/README.md
**/*.{md,rst}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
**/*.{md,rst}: Format commands, code elements, expressions, package names, file names, and paths as inline code.
Use descriptive link text. Avoid raw URLs and weak anchors such as "here" or "read more."
Use title case consistently for technical documentation headings.
Introduce code blocks, lists, tables, and images with complete sentences.
Write procedures as imperative steps. Keep steps parallel and split long procedures into smaller tasks.
Prefer active voice, present tense, short sentences, contractions, and plain English.
Usecanfor possibility and reservemayfor permission.
Useafterfor temporal relationships instead ofonce.
Preferrefer tooverseewhen the wording points readers to another resource.
Avoid culture-specific idioms, unnecessary Latinisms, jokes, and marketing exaggeration in technical docs.
Spell out months in body text, avoid ordinal dates, and use clear time zones.
Spell out whole numbers from zero through nine unless they are technical values, parameters, versions, or UI values.
Use numerals for 10 or greater and include commas in thousands.
Do not add trademark symbols to learning-oriented docs unless the source, platform, or legal guidance explicitly requires them.
Files:
examples/rust-native-plugin/README.md
{docs/**,README.md,CONTRIBUTING.md,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run docs link validation with
just docs-linkcheckwhen links change
Files:
examples/rust-native-plugin/README.md
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes
Files:
examples/rust-native-plugin/README.md
**/*.{md,mdx,py,sh,yaml,yml,toml,json}
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Keep package names, repo references, and build commands current
Files:
examples/rust-native-plugin/README.md
**/*.{html,md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in HTML and Markdown files using HTML comment syntax
Files:
examples/rust-native-plugin/README.md
**/README.md
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update relevant crate or package README when that surface changed
Files:
examples/rust-native-plugin/README.md
crates/core/src/api/runtime/callbacks.rs
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Define or reuse callback type aliases in
crates/core/src/api/runtime/callbacks.rsusingBox<dyn Fn(...)>pattern for new middleware types
Files:
crates/core/src/api/runtime/callbacks.rs
crates/core/src/api/runtime/state.rs
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
crates/core/src/api/runtime/state.rs: Add registry fields asSortedRegistry<GuardrailEntry<T>>orSortedRegistry<Intercept<T>>toNemoRelayContextStateincrates/core/src/api/runtime/state.rs
Add chain execution helpers toNemoRelayContextStatefollowing the pattern of existing methods liketool_sanitize_request_chainortool_request_intercepts_chain
Files:
crates/core/src/api/runtime/state.rs
crates/core/src/api/registry.rs
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Use existing
global_*_registry_api!andscope_*_registry_api!macro patterns incrates/core/src/api/registry.rsfor both global and scope-local registration APIs unless design explicitly rules one out
Files:
crates/core/src/api/registry.rs
crates/core/src/api/{tool,llm}.rs
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Wire the new middleware chain into the execute path in
crates/core/src/api/tool.rsorcrates/core/src/api/llm.rsat the appropriate pipeline stage
Files:
crates/core/src/api/llm.rs
🔇 Additional comments (19)
crates/core/tests/fixtures/native_plugin/src/lib.rs (1)
8-11: LGTM!Also applies to: 117-139
examples/rust-native-plugin/src/lib.rs (1)
5-7: LGTM!Also applies to: 236-255
examples/rust-native-plugin/README.md (1)
87-101: LGTM!crates/core/src/plugin.rs (2)
30-39: LGTM!
354-384: 📐 Maintainability & Code QualityVerify required Rust and core-runtime validation before merge.
This PR touches Rust and
crates/core, so please confirmcargo fmt --all,cargo clippy --workspace --all-targets -- -D warnings,just test-rust, and the affected binding matrix passed. As per coding guidelines, "**/*.rs: Any Rust change must runjust test-rust,cargo fmt --all,cargo clippy --workspace --all-targets -- -D warnings" and "{crates/core,crates/adaptive}/**/*: Changes tocrates/coreorcrates/adaptivemust run the full language matrix."Source: Coding guidelines
crates/core/src/plugin/dynamic/native.rs (1)
29-41: LGTM!Also applies to: 1336-1341, 1689-1786
crates/plugin/src/lib.rs (1)
19-22: LGTM!Also applies to: 1495-1527, 2227-2294
crates/core/tests/integration/middleware_tests.rs (1)
17-24: LGTM!Also applies to: 33-40, 2594-2782
crates/core/tests/integration/native_plugin_tests.rs (1)
345-362: LGTM!crates/types/src/api/event.rs (1)
367-389: LGTM!crates/types/src/api/llm.rs (1)
10-18: LGTM!Also applies to: 32-75
crates/core/src/api/runtime/callbacks.rs (1)
18-18: LGTM!Also applies to: 180-189
crates/core/src/api/registry.rs (1)
550-573: 📐 Maintainability & Code QualityConfirm the required core validation matrix ran.
This changes
crates/corerequest-intercept registration and shared runtime behavior, so please verify the broader repo checks ran, not just local Rust compilation:validate-change,just test-rust,cargo fmt --all,cargo clippy --workspace --all-targets -- -D warnings, and the affected binding tests.As per coding guidelines, "If the change touched
crates/coreor shared runtime semantics, also usevalidate-changefor broader validation" and "Changes tocrates/coreorcrates/adaptivemust run the full language matrix."Also applies to: 672-697
Source: Coding guidelines
crates/core/src/api/runtime.rs (1)
14-16: LGTM!crates/core/src/api/llm.rs (2)
6-12: LGTM!Also applies to: 32-32, 302-330, 620-639, 777-796, 852-876
620-639: 🩺 Stability & AvailabilityRun the Rust and binding validation matrix for this LLM lifecycle change. This touches
crates/coreLLM start/end emission on sync and streaming paths, so includecargo fmt --all,cargo clippy --workspace --all-targets -- -D warnings,just test-rust, and the affected binding suites (just test-python,just test-go,just test-node,just test-wasm).crates/core/src/api/runtime/state.rs (1)
23-26: LGTM!Also applies to: 66-66, 1014-1015, 1044-1062
crates/core/src/context/registries.rs (1)
14-14: LGTM!Also applies to: 44-44
crates/core/src/api/shared.rs (1)
77-81: LGTM!
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Unify request-intercept results across the core runtime, native ABI, worker protocol, C, Go, Python, Node.js, and WebAssembly. Add ordered pending lifecycle marks and remove legacy tuple, split-output, and mark-specific registration variants. Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
6e45f14 to
1509dec
Compare
License DiffCompared against Lockfile license changesLockfile License ChangesRustAdded
Removed
Updated/Changed
NodeAdded
Removed
Updated/Changed
PythonAdded
Removed
Updated/Changed
Status output |
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/node/tests/llm_tests.mjs (1)
829-858: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winGood coverage of camelCase normalization; consider adding a negative test for unknown pending-mark fields.
JsPendingMarkSpecnow usesdeny_unknown_fields, so a caller passing a stray/legacycategory_profilekey should be rejected. This test suite only covers the happy path with valid camelCase keys.As per path instructions,
Tests should cover the behavior promised by the changed API surface, including error paths...🤖 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/node/tests/llm_tests.mjs` around lines 829 - 858, Add a negative test around llmRequestIntercepts/JsPendingMarkSpec covering rejection of unknown pending-mark fields: verify that a stray or legacy key such as category_profile causes the request parsing to fail instead of being accepted. Keep the existing happy-path camelCase assertions, and extend the llm_tests.mjs coverage near the current pendingMarks case so the deny_unknown_fields behavior is exercised explicitly.
🤖 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/node/src/callable.rs`:
- Around line 37-82: `JsPendingMarkSpec`, its two `From` implementations, and
`js_pending_marks` are duplicated in the Node and Wasm callable modules, so move
this DTO into a shared location that depends only on the
`nemo_relay::api::event` types and re-export it from both bindings. Update the
Node-side `callable` code to use the shared `JsPendingMarkSpec` and keep the
conversion helpers centralized so field additions stay in parity across
bindings.
---
Outside diff comments:
In `@crates/node/tests/llm_tests.mjs`:
- Around line 829-858: Add a negative test around
llmRequestIntercepts/JsPendingMarkSpec covering rejection of unknown
pending-mark fields: verify that a stray or legacy key such as category_profile
causes the request parsing to fail instead of being accepted. Keep the existing
happy-path camelCase assertions, and extend the llm_tests.mjs coverage near the
current pendingMarks case so the deny_unknown_fields behavior is exercised
explicitly.
🪄 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: 78350259-630b-450d-9bea-37e1e76c2e56
📒 Files selected for processing (10)
crates/node/plugin.d.tscrates/node/src/api/mod.rscrates/node/src/callable.rscrates/node/tests/llm_tests.mjscrates/wasm/src/api/mod.rscrates/wasm/src/callable.rscrates/wasm/tests-js/llm_tests.mjscrates/wasm/tests/coverage/callable_tests.rscrates/wasm/wrappers/esm/plugin.d.tsdocs/reference/llm-request-intercept-outcomes.mdx
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: Check / Run
- GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (37)
{crates/adaptive/**,python/nemo_relay/adaptive.py,python/nemo_relay/plugin.py,go/nemo_relay/adaptive/**,go/nemo_relay/!(adaptive)/**,**/node/**,**/wasm/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Keep adaptive surface in sync across crates/adaptive, shared plugin behavior in core and bindings, Python adaptive/plugin wrappers in python/nemo_relay/adaptive.py and python/nemo_relay/plugin.py, Go adaptive helpers under go/nemo_relay/adaptive plus shared plugin helpers in go/nemo_relay, and Node/WebAssembly adaptive helpers and plugin wrappers
Files:
crates/node/plugin.d.tscrates/wasm/tests-js/llm_tests.mjscrates/wasm/src/api/mod.rscrates/wasm/tests/coverage/callable_tests.rscrates/node/src/api/mod.rscrates/wasm/wrappers/esm/plugin.d.tscrates/node/tests/llm_tests.mjscrates/node/src/callable.rscrates/wasm/src/callable.rs
{crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
{crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**}: Maintain consistent plugin lifecycle across all language bindings (Python, Go, Node/WebAssembly, and Rust)
Keep plugin context surfaces aligned across all language implementations
Files:
crates/node/plugin.d.tscrates/wasm/tests-js/llm_tests.mjscrates/wasm/src/api/mod.rscrates/wasm/tests/coverage/callable_tests.rscrates/node/src/api/mod.rscrates/wasm/wrappers/esm/plugin.d.tscrates/node/tests/llm_tests.mjscrates/node/src/callable.rscrates/wasm/src/callable.rs
**/*.{wasm,js,ts}{,x}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure WebAssembly package naming conventions are consistent with generated package expectations and downstream consumption
Files:
crates/node/plugin.d.tscrates/wasm/wrappers/esm/plugin.d.ts
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-nodeto validate public API docstring checks when surface docs changed
Files:
crates/node/plugin.d.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run Node.js formatting with
npm run format --workspace=nemo-relay-nodeInclude SPDX license header in all JavaScript and TypeScript source files using double-slash comment syntax
Files:
crates/node/plugin.d.tscrates/wasm/wrappers/esm/plugin.d.ts
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/node/plugin.d.tscrates/wasm/src/api/mod.rscrates/wasm/tests/coverage/callable_tests.rscrates/node/src/api/mod.rscrates/wasm/wrappers/esm/plugin.d.tscrates/node/src/callable.rscrates/wasm/src/callable.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/node/plugin.d.tscrates/wasm/src/api/mod.rscrates/wasm/tests/coverage/callable_tests.rscrates/node/src/api/mod.rscrates/wasm/wrappers/esm/plugin.d.tscrates/node/src/callable.rscrates/wasm/src/callable.rs
crates/node/**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Node.js public entry points include the main runtime package plus
nemo-relay-node/typed,nemo-relay-node/plugin, andnemo-relay-node/adaptive.
Files:
crates/node/plugin.d.ts
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile third_party/ # P...
Files:
crates/node/plugin.d.tscrates/wasm/tests-js/llm_tests.mjscrates/wasm/src/api/mod.rscrates/wasm/tests/coverage/callable_tests.rscrates/node/src/api/mod.rscrates/wasm/wrappers/esm/plugin.d.tsdocs/reference/llm-request-intercept-outcomes.mdxcrates/node/tests/llm_tests.mjscrates/node/src/callable.rscrates/wasm/src/callable.rs
crates/{python,ffi,node,wasm}/**/*
⚙️ CodeRabbit configuration file
crates/{python,ffi,node,wasm}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.
Files:
crates/node/plugin.d.tscrates/wasm/tests-js/llm_tests.mjscrates/wasm/src/api/mod.rscrates/wasm/tests/coverage/callable_tests.rscrates/node/src/api/mod.rscrates/wasm/wrappers/esm/plugin.d.tscrates/node/tests/llm_tests.mjscrates/node/src/callable.rscrates/wasm/src/callable.rs
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/wasm/src/api/mod.rscrates/wasm/tests/coverage/callable_tests.rscrates/node/src/api/mod.rscrates/node/src/callable.rscrates/wasm/src/callable.rs
crates/wasm/src/api/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Update WebAssembly binding in
crates/wasm/src/api/mod.rsfor language-native bindings
Files:
crates/wasm/src/api/mod.rs
crates/wasm/src/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
camelCasenaming convention for WebAssembly identifiers (e.g.,toolCall)
Files:
crates/wasm/src/api/mod.rscrates/wasm/src/callable.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/wasm/src/api/mod.rscrates/wasm/tests/coverage/callable_tests.rscrates/node/src/api/mod.rscrates/node/src/callable.rscrates/wasm/src/callable.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/wasm/src/api/mod.rscrates/wasm/tests/coverage/callable_tests.rscrates/node/src/api/mod.rscrates/node/src/callable.rscrates/wasm/src/callable.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/wasm/src/api/mod.rscrates/wasm/tests/coverage/callable_tests.rscrates/node/src/api/mod.rscrates/node/src/callable.rscrates/wasm/src/callable.rs
crates/wasm/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-wasm-binding/SKILL.md)
Run
cargo test -p nemo-relay-wasmwhen Rust-only WebAssembly helpers changed
Files:
crates/wasm/src/api/mod.rscrates/wasm/tests/coverage/callable_tests.rscrates/wasm/src/callable.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/wasm/src/api/mod.rscrates/wasm/tests/coverage/callable_tests.rscrates/node/src/api/mod.rscrates/node/src/callable.rscrates/wasm/src/callable.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
crates/wasm/tests/coverage/callable_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/wasm/tests/coverage/callable_tests.rscrates/node/tests/llm_tests.mjs
crates/node/src/api/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Update Node.js binding in
crates/node/src/api/mod.rsfor language-native bindings
Files:
crates/node/src/api/mod.rs
crates/node/src/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
camelCasenaming convention for Node.js identifiers (e.g.,toolCall)
Files:
crates/node/src/api/mod.rscrates/node/src/callable.rs
crates/wasm/{wrappers,tests-js,scripts}/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.agents/skills/test-wasm-binding/SKILL.md)
Format changed WebAssembly JS/TS wrapper files with
npm run precommit:format --workspace=nemo-relay-node -- crates/wasm/wrappers crates/wasm/tests-js crates/wasm/scripts
Files:
crates/wasm/wrappers/esm/plugin.d.ts
crates/wasm/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run WebAssembly formatting with
npm run precommit:format --workspace=nemo-relay-node -- crates/wasm/wrappers crates/wasm/tests-js crates/wasm/scripts
Files:
crates/wasm/wrappers/esm/plugin.d.ts
{docs/**,README.md,CONTRIBUTING.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Usejust docsfor docs-site builds andjust docs-linkcheckwhen links changed
Run docs site build withjust docs
Files:
docs/reference/llm-request-intercept-outcomes.mdx
{docs/**,README.md,CONTRIBUTING.md,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run docs link validation with
just docs-linkcheckwhen links change
Files:
docs/reference/llm-request-intercept-outcomes.mdx
{docs/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify README and docs entry points still match current package names and paths for large or public-facing changes
Files:
docs/reference/llm-request-intercept-outcomes.mdx
{docs/**,examples/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify examples still run with documented commands for large or public-facing changes
Files:
docs/reference/llm-request-intercept-outcomes.mdx
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes
Files:
docs/reference/llm-request-intercept-outcomes.mdx
**/*.{md,mdx,py,sh,yaml,yml,toml,json}
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Keep package names, repo references, and build commands current
Files:
docs/reference/llm-request-intercept-outcomes.mdx
**/*.mdx
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.
MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)
Files:
docs/reference/llm-request-intercept-outcomes.mdx
**/*.{html,md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in HTML and Markdown files using HTML comment syntax
Files:
docs/reference/llm-request-intercept-outcomes.mdx
docs/reference/**
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update relevant reference documentation for any public API changes
Files:
docs/reference/llm-request-intercept-outcomes.mdx
docs/**/*.{md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed
Files:
docs/reference/llm-request-intercept-outcomes.mdx
docs/**
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run
just docsor./scripts/build-docs.sh htmlto regenerate ignored Fern API reference pages before validation for documentation site changes
Files:
docs/reference/llm-request-intercept-outcomes.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/reference/llm-request-intercept-outcomes.mdx
🧠 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.tscrates/wasm/wrappers/esm/plugin.d.ts
🔇 Additional comments (14)
crates/node/plugin.d.ts (1)
85-95: LGTM!crates/wasm/tests-js/llm_tests.mjs (1)
207-236: LGTM!crates/wasm/src/api/mod.rs (1)
2039-2043: LGTM!crates/wasm/tests/coverage/callable_tests.rs (2)
17-41: LGTM!
42-48: 🎯 Functional CorrectnessNo issue here
JsPendingMarkSpecalready uses#[serde(rename_all = "camelCase", deny_unknown_fields)], socategory_profileis rejected as intended.> Likely an incorrect or invalid review comment.crates/wasm/wrappers/esm/plugin.d.ts (1)
83-94: LGTM!crates/wasm/src/callable.rs (2)
50-95: Same duplication concern ascrates/node/src/callable.rs(JsPendingMarkSpec+ conversions defined identically in both crates).
390-411: LGTM!crates/node/src/api/mod.rs (2)
2951-2953: LGTM!Also applies to: 2963-2969
2262-2264: 🗄️ Data Integrity & IntegrationNeed the
EventCategorytype definition and serde implementation before changing the serialization path.docs/reference/llm-request-intercept-outcomes.mdx (1)
60-69: LGTM!crates/node/tests/llm_tests.mjs (2)
595-595: LGTM!
732-732: LGTM!Also applies to: 772-772
crates/node/src/callable.rs (1)
297-313: LGTM!
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
There was a problem hiding this comment.
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/wasm/src/callable.rs`:
- Around line 38-40: The unconditional js_pending_marks re-export in callable.rs
should be gated the same way as JsPendingMarkSpec so non-wasm builds do not keep
an unused import and fail clippy. Update the imports in the callable module so
js_pending_marks is only available under the wasm/test cfg, matching its use in
the wasm-only intercept wrapper, and leave the existing target_arch gating
behavior intact.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 7e841ff3-9a4f-4243-9aff-95ffe3e5fcb7
📒 Files selected for processing (26)
crates/core/src/bindings.rscrates/core/src/lib.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/integration/middleware_tests.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/ffi/nemo_relay.hcrates/ffi/src/api/mod.rscrates/ffi/src/callable.rscrates/ffi/tests/unit/api/core_tests.rscrates/node/src/callable.rscrates/python/tests/coverage/py_api_coverage_tests.rscrates/wasm/src/callable.rscrates/wasm/tests/coverage/callable_tests.rscrates/worker/src/lib.rscrates/worker/tests/worker_sdk_tests.rsdocs/build-plugins/register-behavior.mdxdocs/instrument-applications/code-examples.mdxdocs/integrate-into-frameworks/code-examples.mdxgo/nemo_relay/top_level_coverage_test.gopython/plugin/README.mdpython/plugin/src/nemo_relay_plugin/_api.pypython/tests/plugin/test_worker_sdk.pypython/tests/test_codecs.pypython/tests/test_integration_codecs.py
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: Check / Run
- GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (56)
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/core/src/lib.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/wasm/tests/coverage/callable_tests.rscrates/python/tests/coverage/py_api_coverage_tests.rscrates/core/src/bindings.rscrates/ffi/tests/unit/api/core_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/ffi/src/callable.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/worker/src/lib.rscrates/core/src/plugin/dynamic/worker.rscrates/ffi/src/api/mod.rscrates/wasm/src/callable.rscrates/node/src/callable.rscrates/core/tests/integration/middleware_tests.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/core/src/lib.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/wasm/tests/coverage/callable_tests.rscrates/python/tests/coverage/py_api_coverage_tests.rscrates/core/src/bindings.rscrates/ffi/tests/unit/api/core_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/ffi/src/callable.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/worker/src/lib.rscrates/core/src/plugin/dynamic/worker.rscrates/ffi/src/api/mod.rscrates/wasm/src/callable.rscrates/node/src/callable.rscrates/core/tests/integration/middleware_tests.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/core/src/lib.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/wasm/tests/coverage/callable_tests.rscrates/python/tests/coverage/py_api_coverage_tests.rscrates/core/src/bindings.rscrates/ffi/tests/unit/api/core_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/ffi/nemo_relay.hcrates/ffi/src/callable.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/worker/src/lib.rscrates/core/src/plugin/dynamic/worker.rscrates/ffi/src/api/mod.rscrates/wasm/src/callable.rscrates/node/src/callable.rscrates/core/tests/integration/middleware_tests.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/core/src/lib.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/bindings.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/middleware_tests.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/core/src/lib.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/wasm/tests/coverage/callable_tests.rscrates/python/tests/coverage/py_api_coverage_tests.rscrates/core/src/bindings.rscrates/ffi/tests/unit/api/core_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/ffi/src/callable.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/worker/src/lib.rscrates/core/src/plugin/dynamic/worker.rscrates/ffi/src/api/mod.rscrates/wasm/src/callable.rscrates/node/src/callable.rscrates/core/tests/integration/middleware_tests.rs
crates/core/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
If the change touched
crates/coreor shared runtime semantics, also usevalidate-changefor broader validation
crates/core/**/*.rs: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/src/lib.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/bindings.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/middleware_tests.rs
crates/{core,adaptive}/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly
Files:
crates/core/src/lib.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/bindings.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/middleware_tests.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/core/src/lib.rscrates/core/tests/integration/worker_plugin_tests.rspython/tests/test_integration_codecs.pycrates/worker/tests/worker_sdk_tests.rscrates/wasm/tests/coverage/callable_tests.rscrates/python/tests/coverage/py_api_coverage_tests.rscrates/core/src/bindings.rscrates/ffi/tests/unit/api/core_tests.rspython/plugin/README.mdcrates/core/tests/fixtures/worker_plugin/src/main.rscrates/ffi/src/callable.rscrates/core/tests/unit/dynamic_worker_tests.rspython/tests/test_codecs.pycrates/worker/src/lib.rscrates/core/src/plugin/dynamic/worker.rsgo/nemo_relay/top_level_coverage_test.gopython/plugin/src/nemo_relay_plugin/_api.pycrates/ffi/src/api/mod.rscrates/wasm/src/callable.rscrates/node/src/callable.rspython/tests/plugin/test_worker_sdk.pycrates/core/tests/integration/middleware_tests.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/core/src/lib.rscrates/core/tests/integration/worker_plugin_tests.rspython/tests/test_integration_codecs.pycrates/worker/tests/worker_sdk_tests.rscrates/wasm/tests/coverage/callable_tests.rscrates/python/tests/coverage/py_api_coverage_tests.rscrates/core/src/bindings.rscrates/ffi/tests/unit/api/core_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/ffi/src/callable.rscrates/core/tests/unit/dynamic_worker_tests.rspython/tests/test_codecs.pycrates/worker/src/lib.rscrates/core/src/plugin/dynamic/worker.rsgo/nemo_relay/top_level_coverage_test.gopython/plugin/src/nemo_relay_plugin/_api.pycrates/ffi/src/api/mod.rscrates/wasm/src/callable.rscrates/node/src/callable.rspython/tests/plugin/test_worker_sdk.pycrates/core/tests/integration/middleware_tests.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/core/src/lib.rscrates/core/tests/integration/worker_plugin_tests.rscrates/worker/tests/worker_sdk_tests.rscrates/wasm/tests/coverage/callable_tests.rscrates/python/tests/coverage/py_api_coverage_tests.rscrates/core/src/bindings.rscrates/ffi/tests/unit/api/core_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/ffi/src/callable.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/worker/src/lib.rscrates/core/src/plugin/dynamic/worker.rscrates/ffi/src/api/mod.rscrates/wasm/src/callable.rscrates/node/src/callable.rscrates/core/tests/integration/middleware_tests.rs
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings,
documentation, integrations, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile skills/ # Publishe...
Files:
crates/core/src/lib.rscrates/core/tests/integration/worker_plugin_tests.rspython/tests/test_integration_codecs.pycrates/worker/tests/worker_sdk_tests.rscrates/wasm/tests/coverage/callable_tests.rscrates/python/tests/coverage/py_api_coverage_tests.rscrates/core/src/bindings.rscrates/ffi/tests/unit/api/core_tests.rsdocs/instrument-applications/code-examples.mdxpython/plugin/README.mdcrates/core/tests/fixtures/worker_plugin/src/main.rscrates/ffi/nemo_relay.hdocs/build-plugins/register-behavior.mdxcrates/ffi/src/callable.rsdocs/integrate-into-frameworks/code-examples.mdxcrates/core/tests/unit/dynamic_worker_tests.rspython/tests/test_codecs.pycrates/worker/src/lib.rscrates/core/src/plugin/dynamic/worker.rsgo/nemo_relay/top_level_coverage_test.gopython/plugin/src/nemo_relay_plugin/_api.pycrates/ffi/src/api/mod.rscrates/wasm/src/callable.rscrates/node/src/callable.rspython/tests/plugin/test_worker_sdk.pycrates/core/tests/integration/middleware_tests.rs
crates/{core,adaptive}/**/*.rs
⚙️ CodeRabbit configuration file
crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.
Files:
crates/core/src/lib.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/src/bindings.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/src/plugin/dynamic/worker.rscrates/core/tests/integration/middleware_tests.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
crates/core/tests/integration/worker_plugin_tests.rspython/tests/test_integration_codecs.pycrates/worker/tests/worker_sdk_tests.rscrates/wasm/tests/coverage/callable_tests.rscrates/python/tests/coverage/py_api_coverage_tests.rscrates/ffi/tests/unit/api/core_tests.rscrates/core/tests/unit/dynamic_worker_tests.rspython/tests/test_codecs.pygo/nemo_relay/top_level_coverage_test.gopython/tests/plugin/test_worker_sdk.pycrates/core/tests/integration/middleware_tests.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
crates/core/tests/integration/worker_plugin_tests.rspython/tests/test_integration_codecs.pycrates/worker/tests/worker_sdk_tests.rscrates/wasm/tests/coverage/callable_tests.rscrates/python/tests/coverage/py_api_coverage_tests.rscrates/ffi/tests/unit/api/core_tests.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/unit/dynamic_worker_tests.rspython/tests/test_codecs.pygo/nemo_relay/top_level_coverage_test.gopython/tests/plugin/test_worker_sdk.pycrates/core/tests/integration/middleware_tests.rs
**/test_*.{py,py}
📄 CodeRabbit inference engine (.agents/skills/add-integration/SKILL.md)
Relevant integration tests or smoke coverage must exist for the integration path
Files:
python/tests/test_integration_codecs.pypython/tests/test_codecs.pypython/tests/plugin/test_worker_sdk.py
{pyproject.toml,**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Python package names in
pyproject.tomland import paths used throughout the codebase
Files:
python/tests/test_integration_codecs.pypython/tests/test_codecs.pypython/plugin/src/nemo_relay_plugin/_api.pypython/tests/plugin/test_worker_sdk.py
**/*.{py,txt,toml,cfg,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Python package names and top-level module imports during coordinated rename operations
Files:
python/tests/test_integration_codecs.pypython/tests/test_codecs.pypython/plugin/src/nemo_relay_plugin/_api.pypython/tests/plugin/test_worker_sdk.py
python/**/*test*.py
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
python/**/*test*.py: Do not add@pytest.mark.asyncioto any test in Python test files
Do not add a-> Nonereturn type annotation to test functions
When mocking a class, useunittest.mock.MagicMockorunittest.mock.AsyncMockwith thespecconstructor argument when necessary, rather than defining a new class
Prefix mocked class names withmock, notfake
Prefer pytest fixtures over helper methods in Python tests
Preferpytest.mark.parametrizeover creating individual tests for different input types
Files:
python/tests/test_integration_codecs.pypython/tests/test_codecs.pypython/tests/plugin/test_worker_sdk.py
python/**/{conftest.py,*test*.py}
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
When creating a fixture follow the pattern:
@pytest.fixture(name="<fixture_name>"[, scope="<scope>"]) def <fixture_name>_fixture() -> <return_type>:and only specify the scope argument when the value is something other than "function"
Files:
python/tests/test_integration_codecs.pypython/tests/test_codecs.pypython/tests/plugin/test_worker_sdk.py
**/*.py
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*.py: Run Python formatting withuv run ruff format python
Run Python testing withuv run pytest -k "<pattern>"
**/*.py: Use Ruff with rule sets E, F, W, I for Python linting
Use Ruff formatter with line length 120 and double quotes for Python code formatting
Runtyfor Python type checking
Use Python snake_case naming convention for Python identifiers
Include SPDX license header in all Python source files using hash comment syntax
Validate Python code withuv run pre-commit run --all-filesto enforce Ruff linting and formatting, and ty type checking
Files:
python/tests/test_integration_codecs.pypython/tests/test_codecs.pypython/plugin/src/nemo_relay_plugin/_api.pypython/tests/plugin/test_worker_sdk.py
**/*.{md,mdx,py,sh,yaml,yml,toml,json}
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Keep package names, repo references, and build commands current
Files:
python/tests/test_integration_codecs.pydocs/instrument-applications/code-examples.mdxpython/plugin/README.mddocs/build-plugins/register-behavior.mdxdocs/integrate-into-frameworks/code-examples.mdxpython/tests/test_codecs.pypython/plugin/src/nemo_relay_plugin/_api.pypython/tests/plugin/test_worker_sdk.py
{crates/adaptive/**,python/nemo_relay/adaptive.py,python/nemo_relay/plugin.py,go/nemo_relay/adaptive/**,go/nemo_relay/!(adaptive)/**,**/node/**,**/wasm/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Keep adaptive surface in sync across crates/adaptive, shared plugin behavior in core and bindings, Python adaptive/plugin wrappers in python/nemo_relay/adaptive.py and python/nemo_relay/plugin.py, Go adaptive helpers under go/nemo_relay/adaptive plus shared plugin helpers in go/nemo_relay, and Node/WebAssembly adaptive helpers and plugin wrappers
Files:
crates/wasm/tests/coverage/callable_tests.rscrates/wasm/src/callable.rscrates/node/src/callable.rs
{crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
{crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**}: Maintain consistent plugin lifecycle across all language bindings (Python, Go, Node/WebAssembly, and Rust)
Keep plugin context surfaces aligned across all language implementations
Files:
crates/wasm/tests/coverage/callable_tests.rsgo/nemo_relay/top_level_coverage_test.gocrates/wasm/src/callable.rscrates/node/src/callable.rs
crates/wasm/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-wasm-binding/SKILL.md)
Run
cargo test -p nemo-relay-wasmwhen Rust-only WebAssembly helpers changed
Files:
crates/wasm/tests/coverage/callable_tests.rscrates/wasm/src/callable.rs
crates/{python,ffi,node,wasm}/**/*
⚙️ CodeRabbit configuration file
crates/{python,ffi,node,wasm}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.
Files:
crates/wasm/tests/coverage/callable_tests.rscrates/python/tests/coverage/py_api_coverage_tests.rscrates/ffi/tests/unit/api/core_tests.rscrates/ffi/nemo_relay.hcrates/ffi/src/callable.rscrates/ffi/src/api/mod.rscrates/wasm/src/callable.rscrates/node/src/callable.rs
crates/python/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
If the native Rust bridge changed, add the Rust crate tests for
nemo-relay-python
Files:
crates/python/tests/coverage/py_api_coverage_tests.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/tests/unit/api/core_tests.rscrates/ffi/nemo_relay.hcrates/ffi/src/callable.rscrates/ffi/src/api/mod.rs
crates/ffi/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
If the change touched
crates/ffi, also usetest-ffi-surfacefor validation
Files:
crates/ffi/tests/unit/api/core_tests.rscrates/ffi/src/callable.rscrates/ffi/src/api/mod.rs
{docs/**,README.md,CONTRIBUTING.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Usejust docsfor docs-site builds andjust docs-linkcheckwhen links changed
Run docs site build withjust docs
Files:
docs/instrument-applications/code-examples.mdxdocs/build-plugins/register-behavior.mdxdocs/integrate-into-frameworks/code-examples.mdx
{docs/**,README.md,CONTRIBUTING.md,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Run docs link validation with
just docs-linkcheckwhen links change
Files:
docs/instrument-applications/code-examples.mdxpython/plugin/README.mddocs/build-plugins/register-behavior.mdxdocs/integrate-into-frameworks/code-examples.mdx
{docs/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify README and docs entry points still match current package names and paths for large or public-facing changes
Files:
docs/instrument-applications/code-examples.mdxdocs/build-plugins/register-behavior.mdxdocs/integrate-into-frameworks/code-examples.mdx
{docs/**,examples/**,README.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Verify examples still run with documented commands for large or public-facing changes
Files:
docs/instrument-applications/code-examples.mdxdocs/build-plugins/register-behavior.mdxdocs/integrate-into-frameworks/code-examples.mdx
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes
Files:
docs/instrument-applications/code-examples.mdxpython/plugin/README.mddocs/build-plugins/register-behavior.mdxdocs/integrate-into-frameworks/code-examples.mdx
**/*.mdx
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.
MDX top-of-file SPDX comments must use {/* ... */} delimiters instead of HTML comment delimiters (Must-Fix)
Files:
docs/instrument-applications/code-examples.mdxdocs/build-plugins/register-behavior.mdxdocs/integrate-into-frameworks/code-examples.mdx
**/*.{html,md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Include SPDX license header in HTML and Markdown files using HTML comment syntax
Files:
docs/instrument-applications/code-examples.mdxpython/plugin/README.mddocs/build-plugins/register-behavior.mdxdocs/integrate-into-frameworks/code-examples.mdx
docs/**/*.{md,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed
Files:
docs/instrument-applications/code-examples.mdxdocs/build-plugins/register-behavior.mdxdocs/integrate-into-frameworks/code-examples.mdx
docs/**
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Run
just docsor./scripts/build-docs.sh htmlto regenerate ignored Fern API reference pages before validation for documentation site changes
Files:
docs/instrument-applications/code-examples.mdxdocs/build-plugins/register-behavior.mdxdocs/integrate-into-frameworks/code-examples.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/instrument-applications/code-examples.mdxdocs/build-plugins/register-behavior.mdxdocs/integrate-into-frameworks/code-examples.mdx
**/*.{md,rst,html,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
**/*.{md,rst,html,txt}: Always spellNVIDIAin all caps. Do not useNvidia,nvidia,nVidia,nVIDIA, orNV.
Usean NVIDIAbefore a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol afterNVIDIAwhen referring to the company.
Use trademark symbols with product names only when the document type or legal guidance requires them.
Verify official capitalization, spacing, and hyphenation for product names.
Precede NVIDIA product names withNVIDIAon first mention when it is natural and accurate.
Do not rewrite product names for grammar or title-case rules.
Preserve third-party product names according to the owner's spelling.
Include the company name and full model qualifier on first use when it helps identify the model.
Preserve the official capitalization and punctuation of model names.
Use shorter family names only after the full name is established.
Spell out a term on first use and put the acronym in parentheses unless the acronym is widely understood by the intended audience.
Use the acronym on later mentions after it has been defined.
For long documents, reintroduce the full term if readers might lose context.
Form plurals of acronyms withs, not an apostrophe, such asGPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such asCPU,GPU,PC,API, andUIusually do not need to be spelled out for developer audiences.
Files:
python/plugin/README.md
**/*.{md,rst,html}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
Link the first mention of a product name when the destination helps the reader.
Files:
python/plugin/README.md
**/*.md
📄 CodeRabbit inference engine (.agents/skills/contribute-integration/SKILL.md)
Documentation must be updated if activation or usage changed
**/*.md: Use title case consistently in technical documentation headings
Avoid quotation marks, ampersands, and exclamation marks in headings
Keep product, event, research, and whitepaper names in their official title case
Use title case for table headers
Do not force social-media sentence case into technical docs
Format code elements, commands, parameters, package names, and expressions in monospace
Format directories, file names, and paths in monospace using backticks
Use angle brackets inside monospace for variables inside paths, such as/home/<username>/.login
Format error messages and strings in quotation marks, keeping literal code strings in code formatting when clearer
Format UI buttons, menus, fields, and labels in bold
Use angle brackets between UI labels for menu paths, such as File > Save As
Use italics for new terms on first use, sparingly and only when introducing the term
Use italics for publication titles
Format keyboard shortcuts in plain text, such as Press Ctrl+Alt+Delete
Use owner/repo link text for GitHub repositories, preferring[NVIDIA/NeMo](link)over prose references like 'the GitHub repo'
Introduce every code block with a complete sentence
Do not make a code block complete the grammar of the previous sentence
Do not continue a sentence after a code block
Use syntax highlighting when the format supports it for code blocks
Avoid the word 'snippet' unless the surrounding docs already use it as a term of art
Keep inline method, function, and class references consistent with nearby docs, omitting empty parentheses for prose readability when no call is shown
Use descriptive anchor text that matches the destination title when possible for links
Avoid raw URLs in running text
Avoid generic anchor text such as 'here,' 'this page,' and 'read more'
Include acronyms in link text when a linked term includes an acronym
Do not link long sentences or multiple sentences
Avoid links ...
Files:
python/plugin/README.md
**/{docs,examples,**/*.md,*.patch,*.diff,.github,*.sh,*.yaml,*.yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update documentation, examples, CI configuration, and patch artifacts when performing rename operations
Files:
python/plugin/README.md
**/*.{md,rst,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
Spell
NVIDIAin all caps. Do not useNvidia,nvidia, orNV.
Files:
python/plugin/README.md
**/*.{md,rst}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
**/*.{md,rst}: Format commands, code elements, expressions, package names, file names, and paths as inline code.
Use descriptive link text. Avoid raw URLs and weak anchors such as "here" or "read more."
Use title case consistently for technical documentation headings.
Introduce code blocks, lists, tables, and images with complete sentences.
Write procedures as imperative steps. Keep steps parallel and split long procedures into smaller tasks.
Prefer active voice, present tense, short sentences, contractions, and plain English.
Usecanfor possibility and reservemayfor permission.
Useafterfor temporal relationships instead ofonce.
Preferrefer tooverseewhen the wording points readers to another resource.
Avoid culture-specific idioms, unnecessary Latinisms, jokes, and marketing exaggeration in technical docs.
Spell out months in body text, avoid ordinal dates, and use clear time zones.
Spell out whole numbers from zero through nine unless they are technical values, parameters, versions, or UI values.
Use numerals for 10 or greater and include commas in thousands.
Do not add trademark symbols to learning-oriented docs unless the source, platform, or legal guidance explicitly requires them.
Files:
python/plugin/README.md
**/README.md
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Update relevant crate or package README when that surface changed
Files:
python/plugin/README.md
**/*.{h,c}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update C header names and symbol prefixes during coordinated rename operations
Files:
crates/ffi/nemo_relay.h
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
Ensure FFI header sync for
crates/ffi/nemo_relay.hthrough Cargo/build.rs
Files:
crates/ffi/nemo_relay.h
crates/ffi/*.h
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Prefix C FFI exports with
nemo_relay_
Files:
crates/ffi/nemo_relay.h
go/nemo_relay/**/*.go
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Update Go wrapper in
go/nemo_relay/nemo_relay.gowith doc comment and shorthand package if the capability belongs there
go/nemo_relay/**/*.go: Format changed Go packages withcd go/nemo_relay && go fmt ./...
Run Go tests withjust test-goto build and test the NeMo Relay Go binding
Usejust build-gowhen you want an explicit build-only pass or need the artifact for other work
Usejust ci=true test-gowhen you need the CI-style coverage and JUnit path
On macOS, setDYLD_LIBRARY_PATHto the../../target/releasedirectory before running the rawgo testcommand directly
Files:
go/nemo_relay/top_level_coverage_test.go
go/**/*.go
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
PascalCasenaming convention for Go identifiers (e.g.,nemo_relay.ToolCall)Run Go formatting with
cd go/nemo_relay && go fmt ./...
Files:
go/nemo_relay/top_level_coverage_test.go
{go/nemo_relay/go.mod,go/**/*.go}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure Go module path in
go/nemo_relay/go.modmatches import statements in Go source files
Files:
go/nemo_relay/top_level_coverage_test.go
**/*.go
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Go module paths and package paths during coordinated rename operations
**/*.go: Usegofmtfor Go code formatting
Rungo vet ./...for Go static analysis
Use Go PascalCase naming convention for Go identifiers
Include SPDX license header in all Go source files using double-slash comment syntax
Validate Go code withuv run pre-commit run --all-filesto enforce gofmt formatting and go vet static analysis
Files:
go/nemo_relay/top_level_coverage_test.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/top_level_coverage_test.go
crates/ffi/src/api/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
crates/ffi/src/api/**/*.rs: Add or update FFI wrappers in relevantcrates/ffi/src/api/*.rsmodules, re-export throughcrates/ffi/src/api/mod.rs, and ensure generatedcrates/ffi/nemo_relay.hstays correct
Usenemo_relay_prefix for C FFI function names (e.g.,nemo_relay_tool_call)
Files:
crates/ffi/src/api/mod.rs
crates/wasm/src/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
camelCasenaming convention for WebAssembly identifiers (e.g.,toolCall)
Files:
crates/wasm/src/callable.rs
crates/node/src/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
camelCasenaming convention for Node.js identifiers (e.g.,toolCall)
Files:
crates/node/src/callable.rs
🪛 Ruff (0.15.20)
python/tests/test_codecs.py
[warning] 317-317: Missing return type annotation for private function missing_annotation_intercept
(ANN202)
[warning] 317-317: Unused function argument: name
(ARG001)
[warning] 321-321: Missing return type annotation for private function provider
(ANN202)
[warning] 321-321: Unused function argument: request
(ARG001)
[warning] 326-326: Boolean positional value in function call
(FBT003)
python/tests/plugin/test_worker_sdk.py
[warning] 1617-1617: Dynamically typed expressions (typing.Any) are disallowed in next_call
(ANN401)
[warning] 1671-1671: Dynamically typed expressions (typing.Any) are disallowed in next_call
(ANN401)
[warning] 1723-1723: Dynamically typed expressions (typing.Any) are disallowed in next_call
(ANN401)
🔇 Additional comments (31)
crates/core/src/lib.rs (1)
57-58: LGTM!crates/core/src/bindings.rs (1)
6-60: LGTM! CentralizingJsPendingMarkSpechere (instead of duplicating it in node/wasm callables) resolves the parity-drift concern from prior review rounds.docs/instrument-applications/code-examples.mdx (1)
262-301: LGTM — Python and Node.js tabs now correctly unwrapoutcome.request, matching the Rust example and the canonical outcome API. Past inconsistency is resolved.go/nemo_relay/top_level_coverage_test.go (1)
393-457: LGTM — the raw-content intercept cleanup is now registered viat.Cleanupimmediately after successful registration, so it runs even if a later assertion fails. Resolves the prior leak concern.python/plugin/src/nemo_relay_plugin/_api.py (3)
209-224: LGTM —to_json()correctly validates shape forrequest/annotated_request/pending_marks, and the docstring accurately reflects the new outcome-returning contract.Also applies to: 634-657
1214-1386: LGTM — the task-tracking/cancellation design (_ActiveInvocation,_start_invocation/_forget_invocation,CancelInvocation) is race-free under asyncio's single-threaded model (noawaitbetween check-and-mutate steps), correctly distinguishesBaseException-styleCancelledErrorfrom callback failures, and the "discard buffered chunks after producer finished" behavior inInvokeStreammatches the dedicated test coverage supplied (test_cancel_invocation_discards_buffered_chunks_after_stream_callback_finishes).Also applies to: 1506-1526, 1675-1680
1465-1493: LGTM — handler now strictly enforcesLlmRequestInterceptOutcomeand routes through the canonical outcome envelope, matching the PR's single-outcome contract.crates/node/src/callable.rs (1)
22-28: 📐 Maintainability & Code QualityShared JS pending-mark DTO reuse looks good —
JsPendingMarkSpec/js_pending_marksnow come fromnemo_relay::bindings::js, andSerializeis no longer needed incrates/node/src/callable.rs.crates/core/tests/integration/middleware_tests.rs (2)
2691-2719: Previously flagged assertion gap is now fixed.This resolves the earlier review comment about asserting against the serialized envelope instead of the real provider payload —
provider_request.content.get(...)is now checked directly.
2651-2753: LGTM!crates/core/tests/integration/worker_plugin_tests.rs (1)
185-191: LGTM!Also applies to: 240-295
crates/worker/tests/worker_sdk_tests.rs (1)
234-234: LGTM!Also applies to: 251-436, 1371-1465, 1592-1597
crates/wasm/tests/coverage/callable_tests.rs (1)
7-7: LGTM!Also applies to: 14-16
crates/ffi/src/callable.rs (1)
175-181: 🩺 Stability & AvailabilityNo action needed:
out_outcome_jsonis freed exactly once on all paths.python/tests/test_integration_codecs.py (1)
16-24: 🗄️ Data Integrity & IntegrationLLMRequestInterceptOutcome import is correct
LLMRequestInterceptOutcomeis exported frompython/nemo_relay, and its constructor acceptsrequest,annotated_request, and optionalpending_marks.crates/python/tests/coverage/py_api_coverage_tests.rs (1)
193-202: LGTM!Also applies to: 331-336, 469-476
crates/ffi/tests/unit/api/core_tests.rs (1)
9-62: LGTM! Good regression coverage for the previously-fixed stale-output-pointer issue on theNullPointerpath.crates/core/tests/fixtures/worker_plugin/src/main.rs (1)
8-10: LGTM! Pending-mark coverage now exercises the cross-process pending-mark path as previously requested.Also applies to: 187-209
crates/ffi/nemo_relay.h (1)
258-264: LGTM! Allocator/ownership contract is now documented as previously requested.Also applies to: 412-425
python/tests/test_codecs.py (1)
313-333: LGTM! Closes the codec-error parity gap flagged previously.crates/ffi/src/api/mod.rs (1)
261-322: LGTM! Null-pointer handling now clearsout_outcome_jsonbefore validatingrequest, matching the new regression test.python/tests/plugin/test_worker_sdk.py (2)
207-213: LGTM! Prior fabricated-annotation issue resolved and outcome-shape assertions correctly updated for the new contract.Also applies to: 947-972, 1041-1045, 1160-1162, 1520-1531
1541-1749: LGTM! New cancellation tests correctly exercise idempotent cancel, buffered-chunk discard, and self-cancellation terminal-error paths against the_WorkerServiceimplementation, with timeout guards to avoid hangs.docs/build-plugins/register-behavior.mdx (1)
39-186: LGTM! Past-review discrepancy between the Rust tab and the other bindings' outcome contract is resolved.docs/integrate-into-frameworks/code-examples.mdx (1)
182-218: LGTM! Past-review inconsistency across bindings is resolved.python/plugin/README.md (1)
39-108: LGTM!crates/core/tests/unit/dynamic_worker_tests.rs (1)
492-903: LGTM! Cancellation reason/idempotency assertions line up withcrates/core/src/plugin/dynamic/worker.rsandcrates/worker/src/lib.rs, and the lock-release test directly validates the deadlock-avoidance concern for scope-stack cleanup.Also applies to: 1355-1481, 1496-1630
crates/worker/src/lib.rs (3)
976-1178: LGTM! Generation-tracked cancellation, thereplace_invocationrace handling for stream handoff, and the biased cancellation-aware stream are all sound and consistent with the SDK's documented cancellation contract.Also applies to: 1180-1296, 1712-1781
812-877: 🎯 Functional CorrectnessNo change needed here: the workspace is on Rust 1.93 with edition 2024, so this
if ... && let ...chain is supported.> Likely an incorrect or invalid review comment.
1394-1406: 🗄️ Data Integrity & IntegrationNo change needed: the LLM request-intercept outcome schema already matches the host check, and
has_annotated_requestdoes not exist.requestandannotated_requestare still the supported outcome fields.> Likely an incorrect or invalid review comment.crates/core/src/plugin/dynamic/worker.rs (1)
985-1060: LGTM! The intercept-outcome decoding, invocation-guard cancel/cleanup lifecycle, and the alias-aware scope-stack unwind/condvar coordination are correct and align with the tested concurrency guarantees.Also applies to: 1192-1231, 1257-1334, 1538-1691, 2151-2168
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@python/tests/test_llm.py`:
- Around line 310-312: The global llm intercept registration in the
direct-request test is not cleaned up if an assertion or
llm.request_intercepts() fails. Update the test around
intercepts.register_llm_request and intercepts.deregister_llm_request to use a
try/finally so py_llm_req_direct is always deregistered, and keep the existing
request interception assertions inside the protected block.
- Around line 301-307: The intercept test in the LLM request round-trip path is
mutating the inbound request payload directly, so it does not verify that
LLMRequestInterceptOutcome.request is actually used. Update intercept_fn to copy
request.content before adding the direct flag, then build the outcome from that
copied payload so the assertion covers the returned request object and catches
wrappers that ignore outcome.request.
🪄 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: 9065e9cb-cb02-4b44-9324-91f2e5b1e8d8
📒 Files selected for processing (5)
crates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rsgo/nemo_relay/llm_test.gopython/nemo_relay/intercepts.pypython/tests/test_llm.py
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: Check / Run
- GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (26)
**/test_*.{py,py}
📄 CodeRabbit inference engine (.agents/skills/add-integration/SKILL.md)
Relevant integration tests or smoke coverage must exist for the integration path
Files:
python/tests/test_llm.py
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
python/tests/test_llm.pygo/nemo_relay/llm_test.go
{pyproject.toml,**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Python package names in
pyproject.tomland import paths used throughout the codebase
Files:
python/tests/test_llm.pypython/nemo_relay/intercepts.py
**/*.{py,txt,toml,cfg,yaml,yml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Python package names and top-level module imports during coordinated rename operations
Files:
python/tests/test_llm.pypython/nemo_relay/intercepts.py
python/**/*test*.py
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
python/**/*test*.py: Do not add@pytest.mark.asyncioto any test in Python test files
Do not add a-> Nonereturn type annotation to test functions
When mocking a class, useunittest.mock.MagicMockorunittest.mock.AsyncMockwith thespecconstructor argument when necessary, rather than defining a new class
Prefix mocked class names withmock, notfake
Prefer pytest fixtures over helper methods in Python tests
Preferpytest.mark.parametrizeover creating individual tests for different input types
Files:
python/tests/test_llm.py
python/**/{conftest.py,*test*.py}
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
When creating a fixture follow the pattern:
@pytest.fixture(name="<fixture_name>"[, scope="<scope>"]) def <fixture_name>_fixture() -> <return_type>:and only specify the scope argument when the value is something other than "function"
Files:
python/tests/test_llm.py
**/*.py
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*.py: Run Python formatting withuv run ruff format python
Run Python testing withuv run pytest -k "<pattern>"
**/*.py: Use Ruff with rule sets E, F, W, I for Python linting
Use Ruff formatter with line length 120 and double quotes for Python code formatting
Runtyfor Python type checking
Use Python snake_case naming convention for Python identifiers
Include SPDX license header in all Python source files using hash comment syntax
Validate Python code withuv run pre-commit run --all-filesto enforce Ruff linting and formatting, and ty type checking
Files:
python/tests/test_llm.pypython/nemo_relay/intercepts.py
**/*.{md,mdx,py,sh,yaml,yml,toml,json}
📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)
Keep package names, repo references, and build commands current
Files:
python/tests/test_llm.pypython/nemo_relay/intercepts.py
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
python/tests/test_llm.pypython/nemo_relay/intercepts.pygo/nemo_relay/llm_test.gocrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
python/tests/test_llm.pypython/nemo_relay/intercepts.pygo/nemo_relay/llm_test.gocrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings,
documentation, integrations, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile skills/ # Publishe...
Files:
python/tests/test_llm.pypython/nemo_relay/intercepts.pygo/nemo_relay/llm_test.gocrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
python/tests/test_llm.pygo/nemo_relay/llm_test.gocrates/plugin/tests/typed_callbacks.rs
{crates/python/src/py_api/**/*.rs,python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi}
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Update Python native binding in
crates/python/src/py_api/mod.rswith Python wrapper docstring inpython/nemo_relay/<module>.pyand type stubs inpython/nemo_relay/*.pyimodules
Files:
python/nemo_relay/intercepts.py
python/nemo_relay/**/*.py
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Python identifiers (e.g.,nemo_relay.tools.call)Format changed Python wrapper and test files with
uv run ruff format pythonPython wrapper modules live under
python/nemo_relay/; the native extension is built fromcrates/pythonwithmaturin.
Files:
python/nemo_relay/intercepts.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/intercepts.py
go/nemo_relay/**/*.go
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Update Go wrapper in
go/nemo_relay/nemo_relay.gowith doc comment and shorthand package if the capability belongs there
go/nemo_relay/**/*.go: Format changed Go packages withcd go/nemo_relay && go fmt ./...
Run Go tests withjust test-goto build and test the NeMo Relay Go binding
Usejust build-gowhen you want an explicit build-only pass or need the artifact for other work
Usejust ci=true test-gowhen you need the CI-style coverage and JUnit path
On macOS, setDYLD_LIBRARY_PATHto the../../target/releasedirectory before running the rawgo testcommand directly
Files:
go/nemo_relay/llm_test.go
go/**/*.go
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
PascalCasenaming convention for Go identifiers (e.g.,nemo_relay.ToolCall)Run Go formatting with
cd go/nemo_relay && go fmt ./...
Files:
go/nemo_relay/llm_test.go
{crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
{crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**}: Maintain consistent plugin lifecycle across all language bindings (Python, Go, Node/WebAssembly, and Rust)
Keep plugin context surfaces aligned across all language implementations
Files:
go/nemo_relay/llm_test.go
{go/nemo_relay/go.mod,go/**/*.go}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure Go module path in
go/nemo_relay/go.modmatches import statements in Go source files
Files:
go/nemo_relay/llm_test.go
**/*.go
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Go module paths and package paths during coordinated rename operations
**/*.go: Usegofmtfor Go code formatting
Rungo vet ./...for Go static analysis
Use Go PascalCase naming convention for Go identifiers
Include SPDX license header in all Go source files using double-slash comment syntax
Validate Go code withuv run pre-commit run --all-filesto enforce gofmt formatting and go vet static analysis
Files:
go/nemo_relay/llm_test.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
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rs
🪛 Ruff (0.15.20)
python/tests/test_llm.py
[warning] 301-301: Missing return type annotation for private function intercept_fn
(ANN202)
[warning] 301-301: Unused function argument: name
(ARG001)
[warning] 310-310: Boolean positional value in function call
(FBT003)
🔇 Additional comments (4)
python/nemo_relay/intercepts.py (1)
172-174: LGTM!go/nemo_relay/llm_test.go (1)
532-532: LGTM!crates/plugin/src/lib.rs (1)
2628-2628: LGTM!Also applies to: 2652-2676
crates/plugin/tests/typed_callbacks.rs (1)
4757-4768: LGTM!Also applies to: 4992-4999
willkill07
left a comment
There was a problem hiding this comment.
Approving with nits on:
- structuring of crate-dependent types.
- unnecessary ABI checks.
- suggested
.into()helpers.
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
- add ergonomic outcome conversions and restore registry documentation - keep JavaScript pending-mark DTOs binding-local - remove the unreleased native ABI contract flag Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
crates/node/src/callable.rs (1)
296-312: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAdd
deny_unknown_fieldstoJsOutcome
camelCasemapping is already correct here; adddeny_unknown_fieldsso typos likependingMarkfail instead of being ignored and falling back to an emptypendingMarks.🤖 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/node/src/callable.rs` around lines 296 - 312, `JsOutcome` in `callable.rs` currently accepts unknown JSON fields, which can hide typos in the JS intercept payload. Update the `JsOutcome` struct used in `serde_json::from_value` within the LlmRequest intercept parsing path to reject unknown fields by adding `deny_unknown_fields` alongside the existing `camelCase` rename. Keep the existing field names (`request`, `annotated`, `pending_marks`) intact so malformed keys like `pendingMark` fail during deserialization instead of being silently ignored.Source: Path instructions
crates/plugin/tests/typed_callbacks.rs (1)
281-335: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftBump the native ABI version before shrinking these structs.
Line 281 keeps
NEMO_RELAY_NATIVE_ABI_VERSIONat1, but Lines 299-335 lock in a smallerNemoRelayNativeHostApiV1/NemoRelayNativePluginV1layout. That makes already-built v1 native plugins/workers binary-incompatible with this host, and removing the outcome-contract handshake leaves no explicit rejection path before stale binaries dereference the shortened table. Keep the old v1 layout, or publish this as a new ABI version and reject older plugins at load time.🤖 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/plugin/tests/typed_callbacks.rs` around lines 281 - 335, The typed callback ABI tests are still asserting version 1 while the `NemoRelayNativeHostApiV1`, `NemoRelayNativePluginV1`, and `NemoRelayNativeLlmStreamV1` layouts have been shrunk, which breaks binary compatibility for existing native plugins/workers. Update `NEMO_RELAY_NATIVE_ABI_VERSION` to a new value and treat the changed structs as a new ABI, or preserve the old v1 layouts; also make sure the load path explicitly rejects older binaries instead of letting them use the shortened table. Reference the version constant and the `host_api_offsets()`, `plugin_offsets()`, and `stream_offsets()` shape checks when adjusting the test expectations.
🤖 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/node/src/callable.rs`:
- Around line 296-312: `JsOutcome` in `callable.rs` currently accepts unknown
JSON fields, which can hide typos in the JS intercept payload. Update the
`JsOutcome` struct used in `serde_json::from_value` within the LlmRequest
intercept parsing path to reject unknown fields by adding `deny_unknown_fields`
alongside the existing `camelCase` rename. Keep the existing field names
(`request`, `annotated`, `pending_marks`) intact so malformed keys like
`pendingMark` fail during deserialization instead of being silently ignored.
In `@crates/plugin/tests/typed_callbacks.rs`:
- Around line 281-335: The typed callback ABI tests are still asserting version
1 while the `NemoRelayNativeHostApiV1`, `NemoRelayNativePluginV1`, and
`NemoRelayNativeLlmStreamV1` layouts have been shrunk, which breaks binary
compatibility for existing native plugins/workers. Update
`NEMO_RELAY_NATIVE_ABI_VERSION` to a new value and treat the changed structs as
a new ABI, or preserve the old v1 layouts; also make sure the load path
explicitly rejects older binaries instead of letting them use the shortened
table. Reference the version constant and the `host_api_offsets()`,
`plugin_offsets()`, and `stream_offsets()` shape checks when adjusting the test
expectations.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 2a2a7ae1-ea2f-428a-961f-028a02c56932
📒 Files selected for processing (8)
crates/core/src/api/registry.rscrates/core/src/plugin/dynamic/native.rscrates/node/src/callable.rscrates/plugin/src/lib.rscrates/plugin/tests/typed_callbacks.rscrates/types/src/api/llm.rscrates/types/tests/serialization_tests.rscrates/wasm/src/callable.rs
💤 Files with no reviewable changes (1)
- crates/plugin/src/lib.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: Check / Run
🧰 Additional context used
📓 Path-based instructions (22)
crates/core/src/api/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Implement behavior first in Rust core API modules:
crates/core/src/api/and related core modules such ascrates/core/src/api/runtime/,crates/core/src/codec/, orcrates/core/src/json.rs
Files:
crates/core/src/api/registry.rs
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
snake_casenaming convention for Rust identifiers (e.g.,nemo_relay_tool_call)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node work
**/*.rs: Runcargo fmt --allto format all Rust code
Runcargo clippy --workspace --all-targets -- -D warningsto enforce all clippy lints as errors
**/*.rs: Runcargo fmt --allwhen Rust files changed as part of WebAssembly work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files changed as part of WebAssembly work
**/*.rs: If any Rust code changed, always runjust test-rust
If any Rust code changed, also runcargo fmt --all
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings
Run Rust formatting withcargo fmt --all
Run Rust linting withcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Usecargo fmtfor Rust code formatting
Runcargo clippy -- -D warningsto lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code withuv run pre-commit run --all-filesto enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...
Files:
crates/core/src/api/registry.rscrates/types/src/api/llm.rscrates/types/tests/serialization_tests.rscrates/wasm/src/callable.rscrates/core/src/plugin/dynamic/native.rscrates/node/src/callable.rscrates/plugin/tests/typed_callbacks.rs
crates/core/src/api/registry.rs
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Use existing
global_*_registry_api!andscope_*_registry_api!macro patterns incrates/core/src/api/registry.rsfor both global and scope-local registration APIs unless design explicitly rules one out
Files:
crates/core/src/api/registry.rs
**/{Cargo.toml,**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Maintain consistency between Rust package names in
Cargo.tomland their actual usage across the codebase
Files:
crates/core/src/api/registry.rscrates/types/src/api/llm.rscrates/types/tests/serialization_tests.rscrates/wasm/src/callable.rscrates/core/src/plugin/dynamic/native.rscrates/node/src/callable.rscrates/plugin/tests/typed_callbacks.rs
**/*.{h,hpp,c,cpp,rs}
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Ensure FFI header and library naming follows consistent conventions across platform-specific builds
Files:
crates/core/src/api/registry.rscrates/types/src/api/llm.rscrates/types/tests/serialization_tests.rscrates/wasm/src/callable.rscrates/core/src/plugin/dynamic/native.rscrates/node/src/callable.rscrates/plugin/tests/typed_callbacks.rs
{crates/core,crates/adaptive}/**/*
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
Changes to
crates/coreorcrates/adaptivemust run the full language matrix
Files:
crates/core/src/api/registry.rscrates/core/src/plugin/dynamic/native.rs
**/*.{rs,toml}
📄 CodeRabbit inference engine (.agents/skills/rename-surfaces/SKILL.md)
Update Rust crate names and module prefixes during coordinated rename operations
Files:
crates/core/src/api/registry.rscrates/types/src/api/llm.rscrates/types/tests/serialization_tests.rscrates/wasm/src/callable.rscrates/core/src/plugin/dynamic/native.rscrates/node/src/callable.rscrates/plugin/tests/typed_callbacks.rs
crates/core/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
If the change touched
crates/coreor shared runtime semantics, also usevalidate-changefor broader validation
crates/core/**/*.rs: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths. Keep errors explicit and binding-appropriate at the wrapper layer.
Files:
crates/core/src/api/registry.rscrates/core/src/plugin/dynamic/native.rs
crates/{core,adaptive}/**
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If
crates/coreorcrates/adaptivechanged, run the full matrix across Rust, Python, Go, Node.js, and WebAssembly
Files:
crates/core/src/api/registry.rscrates/core/src/plugin/dynamic/native.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}
📄 CodeRabbit inference engine (AGENTS.md)
Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.
Files:
crates/core/src/api/registry.rscrates/types/src/api/llm.rscrates/types/tests/serialization_tests.rscrates/wasm/src/callable.rscrates/core/src/plugin/dynamic/native.rscrates/node/src/callable.rscrates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions: Rust and Python use
snake_case, C FFI exports prefixednemo_relay_, Go usesPascalCasefor public APIs, Node.js usescamelCase.
Files:
crates/core/src/api/registry.rscrates/types/src/api/llm.rscrates/types/tests/serialization_tests.rscrates/wasm/src/callable.rscrates/core/src/plugin/dynamic/native.rscrates/node/src/callable.rscrates/plugin/tests/typed_callbacks.rs
crates/**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
UseJson = serde_json::Valuein Rust-facing runtime APIs for JSON payload handling.
Files:
crates/core/src/api/registry.rscrates/types/src/api/llm.rscrates/types/tests/serialization_tests.rscrates/wasm/src/callable.rscrates/core/src/plugin/dynamic/native.rscrates/node/src/callable.rscrates/plugin/tests/typed_callbacks.rs
**
⚙️ CodeRabbit configuration file
**:AGENTS.md
This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.
Project Overview
NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.
The shared runtime model is:
- Scope stacks decide where work belongs and which scope-local behavior is visible.
- Middleware registries decide what guardrails and intercepts run around managed calls.
- Plugins install reusable runtime behavior from configuration.
- Events record runtime behavior in ATOF form.
- Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.
Repository Structure
The repository layout separates the Rust runtime, language bindings,
documentation, integrations, and agent-facing skills.crates/ core/ # Rust core runtime crate, published as nemo-relay adaptive/ # Adaptive runtime primitives and plugin components python/ # PyO3 native extension for the Python package ffi/ # Raw C ABI layer used by downstream bindings such as Go node/ # NAPI Node.js binding and JavaScript/TypeScript entry points wasm/ # wasm-bindgen WebAssembly binding and JS wrappers python/ nemo_relay/ # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers tests/ # Python tests go/ nemo_relay/ # Experimental Go CGo binding and tests fern/ # Fern documentation site scripts/ # Stable wrappers and helper scripts; build/test/docs entry points live in justfile skills/ # Publishe...
Files:
crates/core/src/api/registry.rscrates/types/src/api/llm.rscrates/types/tests/serialization_tests.rscrates/wasm/src/callable.rscrates/core/src/plugin/dynamic/native.rscrates/node/src/callable.rscrates/plugin/tests/typed_callbacks.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/registry.rscrates/core/src/plugin/dynamic/native.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Maintain documented and tested validation and report behavior for adaptive surfaces
Files:
crates/types/tests/serialization_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/types/tests/serialization_tests.rscrates/plugin/tests/typed_callbacks.rs
crates/wasm/src/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
camelCasenaming convention for WebAssembly identifiers (e.g.,toolCall)
Files:
crates/wasm/src/callable.rs
{crates/adaptive/**,python/nemo_relay/adaptive.py,python/nemo_relay/plugin.py,go/nemo_relay/adaptive/**,go/nemo_relay/!(adaptive)/**,**/node/**,**/wasm/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Keep adaptive surface in sync across crates/adaptive, shared plugin behavior in core and bindings, Python adaptive/plugin wrappers in python/nemo_relay/adaptive.py and python/nemo_relay/plugin.py, Go adaptive helpers under go/nemo_relay/adaptive plus shared plugin helpers in go/nemo_relay, and Node/WebAssembly adaptive helpers and plugin wrappers
Files:
crates/wasm/src/callable.rscrates/node/src/callable.rs
{crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**}
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
{crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**}: Maintain consistent plugin lifecycle across all language bindings (Python, Go, Node/WebAssembly, and Rust)
Keep plugin context surfaces aligned across all language implementations
Files:
crates/wasm/src/callable.rscrates/node/src/callable.rs
crates/wasm/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/test-wasm-binding/SKILL.md)
Run
cargo test -p nemo-relay-wasmwhen Rust-only WebAssembly helpers changed
Files:
crates/wasm/src/callable.rs
crates/{python,ffi,node,wasm}/**/*
⚙️ CodeRabbit configuration file
crates/{python,ffi,node,wasm}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.
Files:
crates/wasm/src/callable.rscrates/node/src/callable.rs
crates/node/src/**/*.rs
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Use
camelCasenaming convention for Node.js identifiers (e.g.,toolCall)
Files:
crates/node/src/callable.rs
🔇 Additional comments (5)
crates/node/src/callable.rs (3)
37-81: 📐 Maintainability & Code QualityDuplicate
JsPendingMarkSpecDTO vs. wasm binding — already discussed and resolved.Same struct/From-impls/helper as
crates/wasm/src/callable.rs. This was previously flagged in review; per the maintainer's follow-up ("should be moved into this crate"), local per-binding copies were the intentional resolution rather than a shared module. No further action needed here.
22-26: LGTM!
257-268: LGTM!crates/wasm/src/callable.rs (2)
19-19: The pending-mark DTO/helper still looks host-only dead on non-wasm builds.Lines 50-94 are compiled for the host library too, but the new
pendingMarkspath is only consumed from wasm/test code in the supplied context. That can still tripdead_code/unused_importsundercargo clippy --workspace --all-targets -- -D warningsunless these items and matching imports are gated with#[cfg(any(test, target_arch = "wasm32"))]. As per coding guidelines,Run cargo clippy --workspace --all-targets -- -D warnings.Also applies to: 30-30, 50-94
Source: Coding guidelines
50-94: 📐 Maintainability & Code QualityPlease confirm the required Rust/Wasm validation ran for this binding change.
The PR context here does not show the required validation for a
crates/wasm/**/*.rschange. Please confirmcargo fmt --all,cargo clippy --workspace --all-targets -- -D warnings,just test-rust,cargo test -p nemo-relay-wasm, anduv run pre-commit run --all-files. As per coding guidelines,Any Rust change must run just test-rust,Run cargo fmt --all,Run cargo clippy --workspace --all-targets -- -D warnings, andValidate Rust code with uv run pre-commit run --all-files; as per path instructions,crates/wasm/**/*.rs:Run cargo test -p nemo-relay-wasm when Rust-only WebAssembly helpers changed.Sources: Coding guidelines, Path instructions
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
|
/merge |
Overview
Finalize one canonical LLM request-intercept outcome across the Rust runtime, built-in and adaptive plugins, native ABI v1,
grpc-v1workers, public C FFI, Go, Python, Node.js, and WebAssembly.Request intercepts can rewrite the provider request, carry an optional normalized annotation, and schedule ordered marks for the managed LLM lifecycle:
{ "request": {"headers": {}, "content": {}}, "annotated_request": null, "pending_marks": [] }requestis required.annotated_requestdefaults tonull, andpending_marksdefaults to an empty list. Each pending mark contains only its name, optional category and category profile, data, and metadata; Relay continues to own event UUIDs, parent UUIDs, and timestamps.The finalized contract also defines one provider-body source of truth. Without a request codec,
outcome.request.contentis authoritative. With a codec,outcome.annotated_requestis required and authoritative,outcome.request.contentis read-only context, andoutcome.request.headersremains writable.Why
Request intercepts run before Relay creates the managed LLM handle. A mark emitted directly from an intercept therefore cannot reliably attach to that future LLM scope. Returning pending mark specifications lets the lifecycle owner emit them at the correct boundary without leaking control data into provider requests, annotations, codecs, sanitizers, or execution intercepts.
Codec-aware interception also previously allowed two conflicting provider-body representations: an intercept could change both the raw request content and its normalized annotation, while Relay later encoded only the annotation. Making authority explicit prevents raw content edits from being silently discarded.
Details
LlmRequestInterceptOutcomethe only Rust callback result and keep oneregister_llm_request_interceptregistration family for global, scope-local, plugin-context, and adaptive paths.outcome.request.contentas the provider body.outcome.annotated_request, encode the provider body from it, and allow header changes only throughoutcome.request.headers.request.contentmutations or missing annotations at the offending codec-path intercept, before later middleware, LLM lifecycle creation, mark emission, or provider invocation.T, every pending mark atT + 1µsin returned order with the LLM UUID as parent, and LLM end at or afterT + 1µs.Boundary contracts
grpc-v1: return oneJsonEnvelopeusing schemanemo.relay.LlmRequestInterceptOutcome@1.char **out_outcome_jsonand addnemo_relay_llm_request_intercept_outcome_json_new.(LLMRequestInterceptOutcome, error)and expose request, outcome, and pending-mark DTOs.LLMRequestInterceptOutcomeand exportPendingMarkSpec.{ request, annotated?, pendingMarks? }. Binding-owned pending-mark DTOs usecategoryProfile; canonical event and outcome JSON retainscategory_profile.Breaking changes
This intentionally finalizes unpublished contracts in place:
grpc-v1request-intercept result is replaced by the canonical outcome envelope.request.content; malformed outcomes fail before lifecycle creation.categoryProfileinstead of the Rust/wire namecategory_profile.All development native plugins and workers must rebuild against this version.
Where should the reviewer start?
crates/types/src/api/event.rsandcrates/types/src/api/llm.rsfor the canonical data contract.crates/core/src/api/runtime/state.rs,crates/core/src/api/shared.rs,crates/core/src/api/llm.rs, andcrates/core/src/stream.rsfor chaining, codec authority, validation, and lifecycle behavior.crates/plugin/src/lib.rs,crates/core/src/plugin/dynamic/native.rs, andcrates/core/src/plugin/dynamic/worker.rsfor native and worker boundaries.crates/ffi,go/nemo_relay,crates/python,crates/node, andcrates/wasmfor binding contracts and DTO conversion.crates/core/tests/integration/middleware_tests.rs,crates/core/tests/integration/pipeline_tests.rs,crates/plugin/tests/typed_callbacks.rs, and the binding tests for lifecycle, codec-authority, and boundary coverage.The full contract, request-authority diagram, and migration notes are tracked in companion documentation PR #341, which should merge immediately after this PR.
Testing
cargo test --workspace --all-targetscargo clippy --workspace --all-targets -- -D warningscargo fmt --all -- --checkcategoryProfileinput/output conversion and codec-authority rejection.go/nemo_relay/...packages passed, including codec-authority coverage;go vet ./...passes.category_profilespelling.wasm-packand thewasm32-unknown-unknownRust target were not available for the package-level Wasm suite. Environment-dependent socket and external-network tests were not used to validate these binding changes.Related Issues
Summary by CodeRabbit
New Features
Bug Fixes