Skip to content

feat(plugin)!: support pending marks from LLM intercepts#327

Merged
rapids-bot[bot] merged 14 commits into
NVIDIA:mainfrom
bbednarski9:feat/llm-intercept-pending-marks
Jul 1, 2026
Merged

feat(plugin)!: support pending marks from LLM intercepts#327
rapids-bot[bot] merged 14 commits into
NVIDIA:mainfrom
bbednarski9:feat/llm-intercept-pending-marks

Conversation

@bbednarski9

@bbednarski9 bbednarski9 commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Overview

Finalize one canonical LLM request-intercept outcome across the Rust runtime, built-in and adaptive plugins, native ABI v1, grpc-v1 workers, 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": []
}

request is required. annotated_request defaults to null, and pending_marks defaults 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.content is authoritative. With a codec, outcome.annotated_request is required and authoritative, outcome.request.content is read-only context, and outcome.request.headers remains writable.

  • I confirm this contribution is my own work, or I have the right to submit it under this project's license.
  • I searched existing issues and open pull requests, and this does not duplicate existing work.

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

  • Make LlmRequestInterceptOutcome the only Rust callback result and keep one register_llm_request_intercept registration family for global, scope-local, plugin-context, and adaptive paths.
  • Propagate each accepted request and annotation to the next intercept while appending pending marks in effective middleware order.
  • Without a request codec, use outcome.request.content as the provider body.
  • With a request codec, require outcome.annotated_request, encode the provider body from it, and allow header changes only through outcome.request.headers.
  • Reject raw request.content mutations or missing annotations at the offending codec-path intercept, before later middleware, LLM lifecycle creation, mark emission, or provider invocation.
  • Preserve marks from an intercept that breaks the chain; discard all accumulated marks if any intercept fails.
  • Return the complete outcome from standalone request-intercept helpers. These helpers expose pending marks but do not emit them because they do not own an LLM lifecycle.
  • After successful interception, create the LLM handle and capture one subscriber snapshot before emitting lifecycle events.
  • Emit LLM start at T, every pending mark at T + 1µs in returned order with the LLM UUID as parent, and LLM end at or after T + 1µs.
  • Apply the same behavior to streaming and non-streaming managed execution, including provider errors and stream finalization.
  • Keep pending marks separate from provider-visible requests and annotations.

Boundary contracts

  • Native ABI v1: return one host-owned outcome JSON string. Remove the private annotation-envelope transport and append required outcome-contract version fields to both host and plugin descriptor tables so stale binaries fail before callback invocation.
  • grpc-v1: return one JsonEnvelope using schema nemo.relay.LlmRequestInterceptOutcome@1.
  • Public C FFI: return one owned char **out_outcome_json and add nemo_relay_llm_request_intercept_outcome_json_new.
  • Go: return (LLMRequestInterceptOutcome, error) and expose request, outcome, and pending-mark DTOs.
  • Python: return LLMRequestInterceptOutcome and export PendingMarkSpec.
  • Node.js and WebAssembly: return { request, annotated?, pendingMarks? }. Binding-owned pending-mark DTOs use categoryProfile; canonical event and outcome JSON retains category_profile.
  • Rust native and worker SDKs: expose only the canonical callback and registration method.

Breaking changes

This intentionally finalizes unpublished contracts in place:

  • Rust and Python tuple results are removed.
  • C and Go split outputs are removed.
  • Mark-specific parallel registration variants are removed.
  • The native annotation metadata envelope and fallback parser are removed.
  • Native ABI host and plugin tables require the finalized outcome-contract field.
  • The grpc-v1 request-intercept result is replaced by the canonical outcome envelope.
  • Codec-path intercepts must return an annotation and may no longer mutate raw request.content; malformed outcomes fail before lifecycle creation.
  • Node.js and WebAssembly pending-mark objects use categoryProfile instead of the Rust/wire name category_profile.

All development native plugins and workers must rebuild against this version.

Where should the reviewer start?

  1. crates/types/src/api/event.rs and crates/types/src/api/llm.rs for the canonical data contract.
  2. crates/core/src/api/runtime/state.rs, crates/core/src/api/shared.rs, crates/core/src/api/llm.rs, and crates/core/src/stream.rs for chaining, codec authority, validation, and lifecycle behavior.
  3. crates/plugin/src/lib.rs, crates/core/src/plugin/dynamic/native.rs, and crates/core/src/plugin/dynamic/worker.rs for native and worker boundaries.
  4. crates/ffi, go/nemo_relay, crates/python, crates/node, and crates/wasm for binding contracts and DTO conversion.
  5. 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-targets
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo fmt --all -- --check
  • Python codec and worker SDK coverage passes, including malformed codec-path outcomes and canonical worker envelopes.
  • Node.js LLM suite: 38 passed, including categoryProfile input/output conversion and codec-authority rejection.
  • Go: all go/nemo_relay/... packages passed, including codec-authority coverage; go vet ./... passes.
  • Native SDK: 52 passed.
  • Worker SDK: 9 passed; worker protocol tests: 6 passed.
  • C FFI: unit and integration suites passed, including owned outcome allocation and malformed/null input coverage.
  • WebAssembly native Rust tests: 13 passed, including camelCase pending-mark DTO round trips and rejection of the wire-only category_profile spelling.
  • Repository formatting, strict Clippy, Ruff, Prettier, type, lockfile, FFI-header, and applicable pre-commit checks pass.

wasm-pack and the wasm32-unknown-unknown Rust 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

    • LLM request intercepts can now return a unified outcome that includes the rewritten request, optional annotated request, and pending marks.
    • Pending marks are now emitted alongside LLM lifecycle events and supported across SDKs and plugins.
  • Bug Fixes

    • Improved consistency of LLM event timing and parent/child relationships.
    • Added stricter validation so intercepts that modify raw request content or omit required annotations are rejected when needed.

Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

An error occurred during the review process. Please try again later.

Walkthrough

Introduces PendingMarkSpec and LlmRequestInterceptOutcome as the canonical return contract for LLM request-intercept callbacks, replacing tuple/JSON returns across core execution, FFI/native/Node/Python/Go/Worker plugin ABIs, and updates examples, documentation, and tests accordingly.

Changes

LLM Request Intercept Pending Marks

Layer / File(s) Summary
Pending mark and intercept outcome contracts
crates/types/src/api/event.rs, crates/types/src/api/llm.rs, crates/types/tests/serialization_tests.rs
Adds PendingMarkSpec and LlmRequestInterceptOutcome types with constructors, From conversions, and round-trip serialization tests.
Callback contract and registry wiring
crates/core/src/api/runtime/callbacks.rs, crates/core/src/api/registry.rs, crates/core/src/api/runtime/state.rs
Updates LlmRequestInterceptFn and llm_request_intercepts_snapshot_chain to produce/validate outcomes with pending marks and codec-active checks.
Shared codec helper and LLM execution emission
crates/core/src/api/shared.rs, crates/core/src/api/llm.rs
Threads pending marks through run_request_intercepts_with_codec, adds emit_pending_request_marks, and unifies subscriber snapshotting for start/end emission.
Stream wrapper subscriber snapshotting
crates/core/src/stream.rs
Precomputes and reuses event subscribers for end/chunk-mark emission instead of recomputing per event.
Native and worker dynamic plugin loaders, fixtures
crates/core/src/plugin/dynamic/native.rs, crates/core/src/plugin/dynamic/worker.rs, crates/core/tests/fixtures/native_plugin/..., crates/core/tests/fixtures/worker_plugin/...
Updates native/worker ABI loaders to decode the single outcome envelope; fixtures register marks-capable intercepts.
Core integration and unit test coverage
crates/core/tests/integration/*, crates/core/tests/unit/*
Migrates test intercepts to LlmRequestInterceptOutcome and adds pending-mark ordering, timestamp, and codec-rejection tests.
Adaptive crate intercepts and tests
crates/adaptive/src/*, crates/adaptive/tests/*
Updates acg_component/adaptive_hints_intercept and tests to the outcome return contract.
FFI ABI outcome contract
crates/ffi/nemo_relay.h, crates/ffi/src/api/mod.rs, crates/ffi/src/callable.rs, crates/ffi/tests/*
Replaces split request/annotated outputs with a single out_outcome_json, adds an outcome-builder FFI function.
Plugin crate native ABI and typed callbacks
crates/plugin/src/lib.rs, crates/plugin/tests/typed_callbacks.rs
Adds outcome contract-version and single out_outcome_json output; updates typed callback registration and tests.
Node.js binding and tests
crates/node/plugin.d.ts, crates/node/src/*, crates/node/tests/*
Adds pendingMarks typing, deserializes JS outcome shape, and updates intercept tests.
Python native binding
crates/python/src/*, crates/python/tests/*
Adds PyPendingMarkSpec/PyLLMRequestInterceptOutcome, updates callback wrapper and coverage tests.
Python package public API and tests
python/nemo_relay/*, python/tests/*
Re-exports the outcome types and updates docstrings/tests to the outcome return contract.
Python plugin worker SDK outcome encoding
python/plugin/src/nemo_relay_plugin/*, python/plugin/README.md, python/tests/plugin/test_worker_sdk.py
Adds outcome dataclasses/schema validation and updates worker SDK encoding and tests.
Worker crate, proto, and tests
crates/worker-proto/..., crates/worker/src/lib.rs, crates/worker/tests/*
Changes proto LlmRequestInterceptResult to a single outcome field and updates worker SDK accordingly.
Go bindings
go/nemo_relay/*
Replaces callback signature with DTO/outcome types and a single out_outcome_json C ABI output across all Go call sites.
Examples and documentation
examples/rust-native-plugin/*
Updates the native plugin example and README to register marks-capable intercepts.

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
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits and accurately summarizes the main breaking change.
Description check ✅ Passed The description covers the required sections and includes overview, details, reviewer start, testing, and related issue information.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions github-actions Bot added size:L PR is large Feature a new feature lang:rust PR changes/introduces Rust code labels Jun 29, 2026
@github-actions

Copy link
Copy Markdown

@bbednarski9 bbednarski9 marked this pull request as ready for review June 29, 2026 22:00
@bbednarski9 bbednarski9 requested a review from a team as a code owner June 29, 2026 22:00

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

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

⚠️ Outside diff range comments (1)
crates/core/tests/unit/shared_tests.rs (1)

196-221: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add 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_marks after codec.encode would still pass here. Add one intercept that returns a real PendingMarkSpec and assert it survives the Some(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

📥 Commits

Reviewing files that changed from the base of the PR and between bb20b13 and 97c0bd1.

📒 Files selected for processing (20)
  • crates/core/src/api/llm.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/context/registries.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/tests/unit/shared_tests.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/types/src/api/event.rs
  • crates/types/src/api/llm.rs
  • crates/types/tests/serialization_tests.rs
  • examples/rust-native-plugin/README.md
  • examples/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_case naming convention for Rust identifiers (e.g., nemo_relay_tool_call)

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

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

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

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

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

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

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

**/*.rs: Use cargo fmt for Rust code formatting
Run cargo clippy -- -D warnings to 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 with uv run pre-commit run --all-files to enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...

Files:

  • crates/core/tests/unit/shared_tests.rs
  • crates/core/src/context/registries.rs
  • examples/rust-native-plugin/src/lib.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/plugin.rs
  • crates/types/src/api/event.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/runtime.rs
  • crates/types/tests/serialization_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/plugin/src/lib.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/types/src/api/llm.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/llm.rs
  • crates/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.rs
  • crates/types/tests/serialization_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/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.toml and their actual usage across the codebase

Files:

  • crates/core/tests/unit/shared_tests.rs
  • crates/core/src/context/registries.rs
  • examples/rust-native-plugin/src/lib.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/plugin.rs
  • crates/types/src/api/event.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/runtime.rs
  • crates/types/tests/serialization_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/plugin/src/lib.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/types/src/api/llm.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/llm.rs
  • crates/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.rs
  • crates/core/src/context/registries.rs
  • examples/rust-native-plugin/src/lib.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/plugin.rs
  • crates/types/src/api/event.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/runtime.rs
  • crates/types/tests/serialization_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/plugin/src/lib.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/types/src/api/llm.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/plugin/dynamic/native.rs
{crates/core,crates/adaptive}/**/*

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

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

Files:

  • crates/core/tests/unit/shared_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/runtime.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/llm.rs
  • crates/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.rs
  • crates/core/src/context/registries.rs
  • examples/rust-native-plugin/src/lib.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/plugin.rs
  • crates/types/src/api/event.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/runtime.rs
  • crates/types/tests/serialization_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/plugin/src/lib.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/types/src/api/llm.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/plugin/dynamic/native.rs
crates/core/**/*.rs

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

If the change touched crates/core or shared runtime semantics, also use validate-change for broader validation

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

Files:

  • crates/core/tests/unit/shared_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/runtime.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/plugin/dynamic/native.rs
crates/{core,adaptive}/**

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

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

Files:

  • crates/core/tests/unit/shared_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/runtime.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/llm.rs
  • crates/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.rs
  • crates/core/src/context/registries.rs
  • examples/rust-native-plugin/src/lib.rs
  • crates/core/src/api/shared.rs
  • examples/rust-native-plugin/README.md
  • crates/core/src/plugin.rs
  • crates/types/src/api/event.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/runtime.rs
  • crates/types/tests/serialization_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/plugin/src/lib.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/types/src/api/llm.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/llm.rs
  • crates/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 prefixed nemo_relay_, Go uses PascalCase for public APIs, Node.js uses camelCase.

Files:

  • crates/core/tests/unit/shared_tests.rs
  • crates/core/src/context/registries.rs
  • examples/rust-native-plugin/src/lib.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/plugin.rs
  • crates/types/src/api/event.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/runtime.rs
  • crates/types/tests/serialization_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/plugin/src/lib.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/types/src/api/llm.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/llm.rs
  • crates/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.
Use Json = serde_json::Value in Rust-facing runtime APIs for JSON payload handling.

Files:

  • crates/core/tests/unit/shared_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/plugin.rs
  • crates/types/src/api/event.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/runtime.rs
  • crates/types/tests/serialization_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/plugin/src/lib.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/types/src/api/llm.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/llm.rs
  • crates/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:

  1. Scope stacks decide where work belongs and which scope-local behavior is visible.
  2. Middleware registries decide what guardrails and intercepts run around managed calls.
  3. Plugins install reusable runtime behavior from configuration.
  4. Events record runtime behavior in ATOF form.
  5. 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.rs
  • crates/core/src/context/registries.rs
  • examples/rust-native-plugin/src/lib.rs
  • crates/core/src/api/shared.rs
  • examples/rust-native-plugin/README.md
  • crates/core/src/plugin.rs
  • crates/types/src/api/event.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/runtime.rs
  • crates/types/tests/serialization_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/plugin/src/lib.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/types/src/api/llm.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/llm.rs
  • crates/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.rs
  • crates/core/src/context/registries.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/plugin.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/runtime.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/llm.rs
  • crates/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.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/types/tests/serialization_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/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.rs
  • examples/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 as crates/core/src/api/runtime/, crates/core/src/codec/, or crates/core/src/json.rs

Files:

  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/registry.rs
  • crates/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 spell NVIDIA in all caps. Do not use Nvidia, nvidia, nVidia, nVIDIA, or NV.
Use an NVIDIA before a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol after NVIDIA when 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 with NVIDIA on 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 with s, not an apostrophe, such as GPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such as CPU, GPU, PC, API, and UI usually 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 NVIDIA in all caps. Do not use Nvidia, nvidia, or NV.

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.
Use can for possibility and reserve may for permission.
Use after for temporal relationships instead of once.
Prefer refer to over see when 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-linkcheck when 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.rs using Box<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 as SortedRegistry<GuardrailEntry<T>> or SortedRegistry<Intercept<T>> to NemoRelayContextState in crates/core/src/api/runtime/state.rs
Add chain execution helpers to NemoRelayContextState following the pattern of existing methods like tool_sanitize_request_chain or tool_request_intercepts_chain

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! and scope_*_registry_api! macro patterns in crates/core/src/api/registry.rs for both global and scope-local registration APIs unless design explicitly rules one out

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.rs or crates/core/src/api/llm.rs at 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 Quality

Verify required Rust and core-runtime validation before merge.

This PR touches Rust and crates/core, so please confirm cargo 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 run just test-rust, cargo fmt --all, cargo clippy --workspace --all-targets -- -D warnings" and "{crates/core,crates/adaptive}/**/*: Changes to crates/core or crates/adaptive must 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 Quality

Confirm the required core validation matrix ran.

This changes crates/core request-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/core or shared runtime semantics, also use validate-change for broader validation" and "Changes to crates/core or crates/adaptive must 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 & Availability

Run the Rust and binding validation matrix for this LLM lifecycle change. This touches crates/core LLM start/end emission on sync and streaming paths, so include cargo 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!

Comment thread crates/core/src/api/shared.rs Outdated
Comment thread crates/core/src/plugin/dynamic/native.rs Outdated
Comment thread crates/core/tests/integration/native_plugin_tests.rs
Comment thread crates/plugin/tests/typed_callbacks.rs Outdated
Comment thread crates/types/tests/serialization_tests.rs
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
@github-actions

Copy link
Copy Markdown

@willkill07 willkill07 added this to the 0.5 milestone Jun 30, 2026
  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>
@bbednarski9 bbednarski9 force-pushed the feat/llm-intercept-pending-marks branch from 6e45f14 to 1509dec Compare June 30, 2026 20:58
@bbednarski9 bbednarski9 requested a review from lvojtku as a code owner June 30, 2026 20:58
@github-actions github-actions Bot added size:XL PR is extra large lang:go PR changes/introduces Go code lang:js PR changes/introduces Javascript/Typescript code lang:python PR changes/introduces Python code and removed size:L PR is large labels Jun 30, 2026
@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown

License Diff

Compared against origin/main.

Lockfile license changes

Lockfile License Changes

Rust

Added

  • None

Removed

  • None

Updated/Changed

  • None

Node

Added

  • None

Removed

  • None

Updated/Changed

  • None

Python

Added

  • None

Removed

  • None

Updated/Changed

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

Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 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 win

Good coverage of camelCase normalization; consider adding a negative test for unknown pending-mark fields.

JsPendingMarkSpec now uses deny_unknown_fields, so a caller passing a stray/legacy category_profile key 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

📥 Commits

Reviewing files that changed from the base of the PR and between dfb40cf and 5ec1922.

📒 Files selected for processing (10)
  • crates/node/plugin.d.ts
  • crates/node/src/api/mod.rs
  • crates/node/src/callable.rs
  • crates/node/tests/llm_tests.mjs
  • crates/wasm/src/api/mod.rs
  • crates/wasm/src/callable.rs
  • crates/wasm/tests-js/llm_tests.mjs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/wasm/wrappers/esm/plugin.d.ts
  • docs/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.ts
  • crates/wasm/tests-js/llm_tests.mjs
  • crates/wasm/src/api/mod.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/node/src/api/mod.rs
  • crates/wasm/wrappers/esm/plugin.d.ts
  • crates/node/tests/llm_tests.mjs
  • crates/node/src/callable.rs
  • crates/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.ts
  • crates/wasm/tests-js/llm_tests.mjs
  • crates/wasm/src/api/mod.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/node/src/api/mod.rs
  • crates/wasm/wrappers/esm/plugin.d.ts
  • crates/node/tests/llm_tests.mjs
  • crates/node/src/callable.rs
  • crates/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.ts
  • crates/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-node to 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-node

Include SPDX license header in all JavaScript and TypeScript source files using double-slash comment syntax

Files:

  • crates/node/plugin.d.ts
  • crates/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.ts
  • crates/wasm/src/api/mod.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/node/src/api/mod.rs
  • crates/wasm/wrappers/esm/plugin.d.ts
  • crates/node/src/callable.rs
  • crates/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 prefixed nemo_relay_, Go uses PascalCase for public APIs, Node.js uses camelCase.

Files:

  • crates/node/plugin.d.ts
  • crates/wasm/src/api/mod.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/node/src/api/mod.rs
  • crates/wasm/wrappers/esm/plugin.d.ts
  • crates/node/src/callable.rs
  • crates/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, and nemo-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:

  1. Scope stacks decide where work belongs and which scope-local behavior is visible.
  2. Middleware registries decide what guardrails and intercepts run around managed calls.
  3. Plugins install reusable runtime behavior from configuration.
  4. Events record runtime behavior in ATOF form.
  5. 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.ts
  • crates/wasm/tests-js/llm_tests.mjs
  • crates/wasm/src/api/mod.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/node/src/api/mod.rs
  • crates/wasm/wrappers/esm/plugin.d.ts
  • docs/reference/llm-request-intercept-outcomes.mdx
  • crates/node/tests/llm_tests.mjs
  • crates/node/src/callable.rs
  • 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/node/plugin.d.ts
  • crates/wasm/tests-js/llm_tests.mjs
  • crates/wasm/src/api/mod.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/node/src/api/mod.rs
  • crates/wasm/wrappers/esm/plugin.d.ts
  • crates/node/tests/llm_tests.mjs
  • crates/node/src/callable.rs
  • crates/wasm/src/callable.rs
**/*.rs

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

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

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

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

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

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

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

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

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

**/*.rs: Use cargo fmt for Rust code formatting
Run cargo clippy -- -D warnings to 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 with uv run pre-commit run --all-files to enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...

Files:

  • crates/wasm/src/api/mod.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/node/src/api/mod.rs
  • crates/node/src/callable.rs
  • crates/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.rs for 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 camelCase naming convention for WebAssembly identifiers (e.g., toolCall)

Files:

  • crates/wasm/src/api/mod.rs
  • crates/wasm/src/callable.rs
**/{Cargo.toml,**/*.rs}

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

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

Files:

  • crates/wasm/src/api/mod.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/node/src/api/mod.rs
  • crates/node/src/callable.rs
  • crates/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.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/node/src/api/mod.rs
  • crates/node/src/callable.rs
  • crates/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.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/node/src/api/mod.rs
  • crates/node/src/callable.rs
  • crates/wasm/src/callable.rs
crates/wasm/**/*.rs

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

Run cargo test -p nemo-relay-wasm when Rust-only WebAssembly helpers changed

Files:

  • crates/wasm/src/api/mod.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/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.
Use Json = serde_json::Value in Rust-facing runtime APIs for JSON payload handling.

Files:

  • crates/wasm/src/api/mod.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/node/src/api/mod.rs
  • crates/node/src/callable.rs
  • crates/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.rs
  • crates/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.rs for 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 camelCase naming convention for Node.js identifiers (e.g., toolCall)

Files:

  • crates/node/src/api/mod.rs
  • crates/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. Use just docs for docs-site builds and just docs-linkcheck when links changed
Run docs site build with just 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-linkcheck when 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 docs or ./scripts/build-docs.sh html to 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.ts
  • crates/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 Correctness

No issue here

JsPendingMarkSpec already uses #[serde(rename_all = "camelCase", deny_unknown_fields)], so category_profile is 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 as crates/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 & Integration

Need the EventCategory type 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!

Comment thread crates/node/src/callable.rs
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 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

📥 Commits

Reviewing files that changed from the base of the PR and between 5ec1922 and 52e080c.

📒 Files selected for processing (26)
  • crates/core/src/bindings.rs
  • crates/core/src/lib.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/ffi/nemo_relay.h
  • crates/ffi/src/api/mod.rs
  • crates/ffi/src/callable.rs
  • crates/ffi/tests/unit/api/core_tests.rs
  • crates/node/src/callable.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/wasm/src/callable.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/worker/src/lib.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • docs/build-plugins/register-behavior.mdx
  • docs/instrument-applications/code-examples.mdx
  • docs/integrate-into-frameworks/code-examples.mdx
  • go/nemo_relay/top_level_coverage_test.go
  • python/plugin/README.md
  • python/plugin/src/nemo_relay_plugin/_api.py
  • python/tests/plugin/test_worker_sdk.py
  • python/tests/test_codecs.py
  • python/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_case naming convention for Rust identifiers (e.g., nemo_relay_tool_call)

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

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

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

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

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

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

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

**/*.rs: Use cargo fmt for Rust code formatting
Run cargo clippy -- -D warnings to 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 with uv run pre-commit run --all-files to enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...

Files:

  • crates/core/src/lib.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/core/src/bindings.rs
  • crates/ffi/tests/unit/api/core_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/ffi/src/callable.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/ffi/src/api/mod.rs
  • crates/wasm/src/callable.rs
  • crates/node/src/callable.rs
  • crates/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.toml and their actual usage across the codebase

Files:

  • crates/core/src/lib.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/core/src/bindings.rs
  • crates/ffi/tests/unit/api/core_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/ffi/src/callable.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/ffi/src/api/mod.rs
  • crates/wasm/src/callable.rs
  • crates/node/src/callable.rs
  • crates/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.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/core/src/bindings.rs
  • crates/ffi/tests/unit/api/core_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/ffi/nemo_relay.h
  • crates/ffi/src/callable.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/ffi/src/api/mod.rs
  • crates/wasm/src/callable.rs
  • crates/node/src/callable.rs
  • crates/core/tests/integration/middleware_tests.rs
{crates/core,crates/adaptive}/**/*

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

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

Files:

  • crates/core/src/lib.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/bindings.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/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.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/core/src/bindings.rs
  • crates/ffi/tests/unit/api/core_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/ffi/src/callable.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/ffi/src/api/mod.rs
  • crates/wasm/src/callable.rs
  • crates/node/src/callable.rs
  • crates/core/tests/integration/middleware_tests.rs
crates/core/**/*.rs

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

If the change touched crates/core or shared runtime semantics, also use validate-change for broader validation

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

Files:

  • crates/core/src/lib.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/bindings.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/integration/middleware_tests.rs
crates/{core,adaptive}/**

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

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

Files:

  • crates/core/src/lib.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/bindings.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/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.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • python/tests/test_integration_codecs.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/core/src/bindings.rs
  • crates/ffi/tests/unit/api/core_tests.rs
  • python/plugin/README.md
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/ffi/src/callable.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • python/tests/test_codecs.py
  • crates/worker/src/lib.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • go/nemo_relay/top_level_coverage_test.go
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/ffi/src/api/mod.rs
  • crates/wasm/src/callable.rs
  • crates/node/src/callable.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/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 prefixed nemo_relay_, Go uses PascalCase for public APIs, Node.js uses camelCase.

Files:

  • crates/core/src/lib.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • python/tests/test_integration_codecs.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/core/src/bindings.rs
  • crates/ffi/tests/unit/api/core_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/ffi/src/callable.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • python/tests/test_codecs.py
  • crates/worker/src/lib.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • go/nemo_relay/top_level_coverage_test.go
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/ffi/src/api/mod.rs
  • crates/wasm/src/callable.rs
  • crates/node/src/callable.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/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.
Use Json = serde_json::Value in Rust-facing runtime APIs for JSON payload handling.

Files:

  • crates/core/src/lib.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/core/src/bindings.rs
  • crates/ffi/tests/unit/api/core_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/ffi/src/callable.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/ffi/src/api/mod.rs
  • crates/wasm/src/callable.rs
  • crates/node/src/callable.rs
  • crates/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:

  1. Scope stacks decide where work belongs and which scope-local behavior is visible.
  2. Middleware registries decide what guardrails and intercepts run around managed calls.
  3. Plugins install reusable runtime behavior from configuration.
  4. Events record runtime behavior in ATOF form.
  5. 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.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • python/tests/test_integration_codecs.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/core/src/bindings.rs
  • crates/ffi/tests/unit/api/core_tests.rs
  • docs/instrument-applications/code-examples.mdx
  • python/plugin/README.md
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/ffi/nemo_relay.h
  • docs/build-plugins/register-behavior.mdx
  • crates/ffi/src/callable.rs
  • docs/integrate-into-frameworks/code-examples.mdx
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • python/tests/test_codecs.py
  • crates/worker/src/lib.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • go/nemo_relay/top_level_coverage_test.go
  • python/plugin/src/nemo_relay_plugin/_api.py
  • crates/ffi/src/api/mod.rs
  • crates/wasm/src/callable.rs
  • crates/node/src/callable.rs
  • python/tests/plugin/test_worker_sdk.py
  • crates/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.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/bindings.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/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.rs
  • python/tests/test_integration_codecs.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/ffi/tests/unit/api/core_tests.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • python/tests/test_codecs.py
  • go/nemo_relay/top_level_coverage_test.go
  • python/tests/plugin/test_worker_sdk.py
  • crates/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.rs
  • python/tests/test_integration_codecs.py
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/wasm/tests/coverage/callable_tests.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/ffi/tests/unit/api/core_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • python/tests/test_codecs.py
  • go/nemo_relay/top_level_coverage_test.go
  • python/tests/plugin/test_worker_sdk.py
  • crates/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.py
  • python/tests/test_codecs.py
  • python/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.toml and import paths used throughout the codebase

Files:

  • python/tests/test_integration_codecs.py
  • python/tests/test_codecs.py
  • python/plugin/src/nemo_relay_plugin/_api.py
  • python/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.py
  • python/tests/test_codecs.py
  • python/plugin/src/nemo_relay_plugin/_api.py
  • python/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.asyncio to any test in Python test files
Do not add a -> None return type annotation to test functions
When mocking a class, use unittest.mock.MagicMock or unittest.mock.AsyncMock with the spec constructor argument when necessary, rather than defining a new class
Prefix mocked class names with mock, not fake
Prefer pytest fixtures over helper methods in Python tests
Prefer pytest.mark.parametrize over creating individual tests for different input types

Files:

  • python/tests/test_integration_codecs.py
  • python/tests/test_codecs.py
  • python/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.py
  • python/tests/test_codecs.py
  • python/tests/plugin/test_worker_sdk.py
**/*.py

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

**/*.py: Run Python formatting with uv run ruff format python
Run Python testing with uv 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
Run ty for 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 with uv run pre-commit run --all-files to enforce Ruff linting and formatting, and ty type checking

Files:

  • python/tests/test_integration_codecs.py
  • python/tests/test_codecs.py
  • python/plugin/src/nemo_relay_plugin/_api.py
  • python/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.py
  • docs/instrument-applications/code-examples.mdx
  • python/plugin/README.md
  • docs/build-plugins/register-behavior.mdx
  • docs/integrate-into-frameworks/code-examples.mdx
  • python/tests/test_codecs.py
  • python/plugin/src/nemo_relay_plugin/_api.py
  • python/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.rs
  • crates/wasm/src/callable.rs
  • crates/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.rs
  • go/nemo_relay/top_level_coverage_test.go
  • crates/wasm/src/callable.rs
  • crates/node/src/callable.rs
crates/wasm/**/*.rs

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

Run cargo test -p nemo-relay-wasm when Rust-only WebAssembly helpers changed

Files:

  • crates/wasm/tests/coverage/callable_tests.rs
  • 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/tests/coverage/callable_tests.rs
  • crates/python/tests/coverage/py_api_coverage_tests.rs
  • crates/ffi/tests/unit/api/core_tests.rs
  • crates/ffi/nemo_relay.h
  • crates/ffi/src/callable.rs
  • crates/ffi/src/api/mod.rs
  • crates/wasm/src/callable.rs
  • crates/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.rs
  • crates/ffi/nemo_relay.h
  • crates/ffi/src/callable.rs
  • crates/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 use test-ffi-surface for validation

Files:

  • crates/ffi/tests/unit/api/core_tests.rs
  • crates/ffi/src/callable.rs
  • crates/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. Use just docs for docs-site builds and just docs-linkcheck when links changed
Run docs site build with just docs

Files:

  • docs/instrument-applications/code-examples.mdx
  • docs/build-plugins/register-behavior.mdx
  • docs/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-linkcheck when links change

Files:

  • docs/instrument-applications/code-examples.mdx
  • python/plugin/README.md
  • docs/build-plugins/register-behavior.mdx
  • docs/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.mdx
  • docs/build-plugins/register-behavior.mdx
  • docs/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.mdx
  • docs/build-plugins/register-behavior.mdx
  • docs/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.mdx
  • python/plugin/README.md
  • docs/build-plugins/register-behavior.mdx
  • docs/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.mdx
  • docs/build-plugins/register-behavior.mdx
  • docs/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.mdx
  • python/plugin/README.md
  • docs/build-plugins/register-behavior.mdx
  • docs/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.mdx
  • docs/build-plugins/register-behavior.mdx
  • docs/integrate-into-frameworks/code-examples.mdx
docs/**

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run just docs or ./scripts/build-docs.sh html to regenerate ignored Fern API reference pages before validation for documentation site changes

Files:

  • docs/instrument-applications/code-examples.mdx
  • docs/build-plugins/register-behavior.mdx
  • docs/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.mdx
  • docs/build-plugins/register-behavior.mdx
  • docs/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 spell NVIDIA in all caps. Do not use Nvidia, nvidia, nVidia, nVIDIA, or NV.
Use an NVIDIA before a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol after NVIDIA when 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 with NVIDIA on 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 with s, not an apostrophe, such as GPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such as CPU, GPU, PC, API, and UI usually 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 NVIDIA in all caps. Do not use Nvidia, nvidia, or NV.

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.
Use can for possibility and reserve may for permission.
Use after for temporal relationships instead of once.
Prefer refer to over see when 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.h through 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.go with doc comment and shorthand package if the capability belongs there

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

Files:

  • go/nemo_relay/top_level_coverage_test.go
go/**/*.go

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

Use PascalCase naming 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.mod matches 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: Use gofmt for Go code formatting
Run go 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 with uv run pre-commit run --all-files to 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 relevant crates/ffi/src/api/*.rs modules, re-export through crates/ffi/src/api/mod.rs, and ensure generated crates/ffi/nemo_relay.h stays correct
Use nemo_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 camelCase naming 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 camelCase naming 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! Centralizing JsPendingMarkSpec here (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 unwrap outcome.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 via t.Cleanup immediately 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 for request/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 (no await between check-and-mutate steps), correctly distinguishes BaseException-style CancelledError from callback failures, and the "discard buffered chunks after producer finished" behavior in InvokeStream matches 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 enforces LlmRequestInterceptOutcome and routes through the canonical outcome envelope, matching the PR's single-outcome contract.

crates/node/src/callable.rs (1)

22-28: 📐 Maintainability & Code Quality

Shared JS pending-mark DTO reuse looks goodJsPendingMarkSpec/js_pending_marks now come from nemo_relay::bindings::js, and Serialize is no longer needed in crates/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 & Availability

No action needed: out_outcome_json is freed exactly once on all paths.

python/tests/test_integration_codecs.py (1)

16-24: 🗄️ Data Integrity & Integration

LLMRequestInterceptOutcome import is correct

LLMRequestInterceptOutcome is exported from python/nemo_relay, and its constructor accepts request, annotated_request, and optional pending_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 the NullPointer path.

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 clears out_outcome_json before validating request, 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 _WorkerService implementation, 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 with crates/core/src/plugin/dynamic/worker.rs and crates/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, the replace_invocation race 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 Correctness

No 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 & Integration

No change needed: the LLM request-intercept outcome schema already matches the host check, and has_annotated_request does not exist. request and annotated_request are 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

Comment thread crates/wasm/src/callable.rs Outdated
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 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

📥 Commits

Reviewing files that changed from the base of the PR and between 52e080c and 66e8704.

📒 Files selected for processing (5)
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • go/nemo_relay/llm_test.go
  • python/nemo_relay/intercepts.py
  • python/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.py
  • go/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.toml and import paths used throughout the codebase

Files:

  • python/tests/test_llm.py
  • python/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.py
  • python/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.asyncio to any test in Python test files
Do not add a -> None return type annotation to test functions
When mocking a class, use unittest.mock.MagicMock or unittest.mock.AsyncMock with the spec constructor argument when necessary, rather than defining a new class
Prefix mocked class names with mock, not fake
Prefer pytest fixtures over helper methods in Python tests
Prefer pytest.mark.parametrize over 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 with uv run ruff format python
Run Python testing with uv 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
Run ty for 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 with uv run pre-commit run --all-files to enforce Ruff linting and formatting, and ty type checking

Files:

  • python/tests/test_llm.py
  • python/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.py
  • python/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.py
  • python/nemo_relay/intercepts.py
  • go/nemo_relay/llm_test.go
  • crates/plugin/src/lib.rs
  • crates/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 prefixed nemo_relay_, Go uses PascalCase for public APIs, Node.js uses camelCase.

Files:

  • python/tests/test_llm.py
  • python/nemo_relay/intercepts.py
  • go/nemo_relay/llm_test.go
  • crates/plugin/src/lib.rs
  • crates/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:

  1. Scope stacks decide where work belongs and which scope-local behavior is visible.
  2. Middleware registries decide what guardrails and intercepts run around managed calls.
  3. Plugins install reusable runtime behavior from configuration.
  4. Events record runtime behavior in ATOF form.
  5. 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.py
  • python/nemo_relay/intercepts.py
  • go/nemo_relay/llm_test.go
  • crates/plugin/src/lib.rs
  • crates/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.py
  • go/nemo_relay/llm_test.go
  • crates/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.rs with Python wrapper docstring in python/nemo_relay/<module>.py and type stubs in python/nemo_relay/*.pyi modules

Files:

  • python/nemo_relay/intercepts.py
python/nemo_relay/**/*.py

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

Use snake_case naming convention for Python identifiers (e.g., nemo_relay.tools.call)

Format changed Python wrapper and test files with uv run ruff format python

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

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.go with doc comment and shorthand package if the capability belongs there

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

Files:

  • go/nemo_relay/llm_test.go
go/**/*.go

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

Use PascalCase naming 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.mod matches 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: Use gofmt for Go code formatting
Run go 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 with uv run pre-commit run --all-files to 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_case naming convention for Rust identifiers (e.g., nemo_relay_tool_call)

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

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

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

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

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

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

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

**/*.rs: Use cargo fmt for Rust code formatting
Run cargo clippy -- -D warnings to 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 with uv run pre-commit run --all-files to enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...

Files:

  • crates/plugin/src/lib.rs
  • crates/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.toml and their actual usage across the codebase

Files:

  • crates/plugin/src/lib.rs
  • crates/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.rs
  • crates/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.rs
  • crates/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.
Use Json = serde_json::Value in Rust-facing runtime APIs for JSON payload handling.

Files:

  • crates/plugin/src/lib.rs
  • crates/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

Comment thread python/tests/test_llm.py
Comment thread python/tests/test_llm.py
@willkill07 willkill07 changed the title feat(plugin): support pending marks from LLM intercepts feat(plugin)!: support pending marks from LLM intercepts Jul 1, 2026
@github-actions github-actions Bot added the breaking PR introduces a breaking change label Jul 1, 2026

@willkill07 willkill07 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approving with nits on:

  • structuring of crate-dependent types.
  • unnecessary ABI checks.
  • suggested .into() helpers.

Comment thread crates/types/src/api/llm.rs
Comment thread crates/core/src/api/runtime/callbacks.rs
Comment thread crates/core/src/api/registry.rs Outdated
Comment thread crates/core/src/api/registry.rs Outdated
Comment thread crates/plugin/src/lib.rs Outdated
Comment thread crates/core/src/bindings.rs Outdated
Comment thread crates/core/src/lib.rs Outdated
Comment thread crates/node/src/api/mod.rs
Comment thread crates/node/src/callable.rs Outdated
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>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (2)
crates/node/src/callable.rs (1)

296-312: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add deny_unknown_fields to JsOutcome
camelCase mapping is already correct here; add deny_unknown_fields so typos like pendingMark fail instead of being ignored and falling back to an empty pendingMarks.

🤖 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 lift

Bump the native ABI version before shrinking these structs.

Line 281 keeps NEMO_RELAY_NATIVE_ABI_VERSION at 1, but Lines 299-335 lock in a smaller NemoRelayNativeHostApiV1/NemoRelayNativePluginV1 layout. 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

📥 Commits

Reviewing files that changed from the base of the PR and between 66e8704 and 2947398.

📒 Files selected for processing (8)
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/node/src/callable.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/types/src/api/llm.rs
  • crates/types/tests/serialization_tests.rs
  • crates/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 as crates/core/src/api/runtime/, crates/core/src/codec/, or crates/core/src/json.rs

Files:

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

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

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

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

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

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

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

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

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

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

**/*.rs: Use cargo fmt for Rust code formatting
Run cargo clippy -- -D warnings to 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 with uv run pre-commit run --all-files to enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...

Files:

  • crates/core/src/api/registry.rs
  • crates/types/src/api/llm.rs
  • crates/types/tests/serialization_tests.rs
  • crates/wasm/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/node/src/callable.rs
  • crates/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! and scope_*_registry_api! macro patterns in crates/core/src/api/registry.rs for both global and scope-local registration APIs unless design explicitly rules one out

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.toml and their actual usage across the codebase

Files:

  • crates/core/src/api/registry.rs
  • crates/types/src/api/llm.rs
  • crates/types/tests/serialization_tests.rs
  • crates/wasm/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/node/src/callable.rs
  • crates/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.rs
  • crates/types/src/api/llm.rs
  • crates/types/tests/serialization_tests.rs
  • crates/wasm/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/node/src/callable.rs
  • crates/plugin/tests/typed_callbacks.rs
{crates/core,crates/adaptive}/**/*

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

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

Files:

  • crates/core/src/api/registry.rs
  • crates/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.rs
  • crates/types/src/api/llm.rs
  • crates/types/tests/serialization_tests.rs
  • crates/wasm/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/node/src/callable.rs
  • crates/plugin/tests/typed_callbacks.rs
crates/core/**/*.rs

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

If the change touched crates/core or shared runtime semantics, also use validate-change for broader validation

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

Files:

  • crates/core/src/api/registry.rs
  • crates/core/src/plugin/dynamic/native.rs
crates/{core,adaptive}/**

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

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

Files:

  • crates/core/src/api/registry.rs
  • crates/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.rs
  • crates/types/src/api/llm.rs
  • crates/types/tests/serialization_tests.rs
  • crates/wasm/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/node/src/callable.rs
  • crates/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 prefixed nemo_relay_, Go uses PascalCase for public APIs, Node.js uses camelCase.

Files:

  • crates/core/src/api/registry.rs
  • crates/types/src/api/llm.rs
  • crates/types/tests/serialization_tests.rs
  • crates/wasm/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/node/src/callable.rs
  • crates/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.
Use Json = serde_json::Value in Rust-facing runtime APIs for JSON payload handling.

Files:

  • crates/core/src/api/registry.rs
  • crates/types/src/api/llm.rs
  • crates/types/tests/serialization_tests.rs
  • crates/wasm/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/node/src/callable.rs
  • crates/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:

  1. Scope stacks decide where work belongs and which scope-local behavior is visible.
  2. Middleware registries decide what guardrails and intercepts run around managed calls.
  3. Plugins install reusable runtime behavior from configuration.
  4. Events record runtime behavior in ATOF form.
  5. 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.rs
  • crates/types/src/api/llm.rs
  • crates/types/tests/serialization_tests.rs
  • crates/wasm/src/callable.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/node/src/callable.rs
  • crates/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.rs
  • crates/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.rs
  • crates/plugin/tests/typed_callbacks.rs
crates/wasm/src/**/*.rs

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

Use camelCase naming 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.rs
  • crates/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.rs
  • crates/node/src/callable.rs
crates/wasm/**/*.rs

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

Run cargo test -p nemo-relay-wasm when 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.rs
  • crates/node/src/callable.rs
crates/node/src/**/*.rs

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

Use camelCase naming 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 Quality

Duplicate JsPendingMarkSpec DTO 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 pendingMarks path is only consumed from wasm/test code in the supplied context. That can still trip dead_code/unused_imports under cargo clippy --workspace --all-targets -- -D warnings unless 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 Quality

Please 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/**/*.rs change. Please confirm cargo fmt --all, cargo clippy --workspace --all-targets -- -D warnings, just test-rust, cargo test -p nemo-relay-wasm, and uv 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, and Validate 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>
@bbednarski9

Copy link
Copy Markdown
Contributor Author

/merge

@rapids-bot rapids-bot Bot merged commit fef0077 into NVIDIA:main Jul 1, 2026
66 of 67 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants