Skip to content

feat(plugin): add native Rust plugin SDK#306

Open
willkill07 wants to merge 1 commit into
NVIDIA:mainfrom
willkill07:wkk_dynamic-plugin-2-native-sdk
Open

feat(plugin): add native Rust plugin SDK#306
willkill07 wants to merge 1 commit into
NVIDIA:mainfrom
willkill07:wkk_dynamic-plugin-2-native-sdk

Conversation

@willkill07

@willkill07 willkill07 commented Jun 25, 2026

Copy link
Copy Markdown
Member

Overview

Add the Rust native plugin authoring SDK on top of the shared DTO crate.

Stack dependency: this PR cannot be merged until parent stacked PR #305 is merged: #305

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

Details

  • Add nemo-relay-plugin with the stable native C ABI v1.
  • Add the high-level typed Rust authoring layer and callback trampoline tests.
  • Add the standalone native Rust plugin example beside the SDK.

Validation run across the completed stack:

  • cargo test -p nemo-relay-types
  • cargo test -p nemo-relay-plugin
  • cargo test -p nemo-relay-worker-proto
  • cargo test -p nemo-relay-worker
  • cargo check -p nemo-relay-cli

Where should the reviewer start?

Start with crates/plugin/src/lib.rs, then check crates/plugin/tests/typed_callbacks.rs.

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

Summary by CodeRabbit

  • New Features

    • Added a Rust native plugin SDK with a stable ABI and typed callback interfaces for plugin lifecycle, tool/LLM guardrails, and intercepts (including LLM streaming).
    • Added a dynamic Rust native plugin example with configurable JSON validation, request/execution/stream interception, and optional isolated-scope event emission.
  • Tests

    • Added a comprehensive typed-callback test suite covering ABI checks, JSON/error handling, registration cleanup, stream behavior, and panic safety.
  • Documentation

    • Added example README plus plugin build/config manifests.
  • Chores

    • Updated the workspace to include the plugin crate and extended local clean rules for example artifacts.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

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

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a workspace plugin crate, a native Rust plugin SDK, typed callback tests, and a Rust cdylib example plugin with config, docs, and registration wiring.

Changes

Native plugin support

Layer / File(s) Summary
Workspace and manifests
Cargo.toml, crates/plugin/Cargo.toml, examples/rust-native-plugin/Cargo.toml, examples/rust-native-plugin/relay-plugin.toml, examples/rust-native-plugin/.gitignore, examples/rust-native-plugin/README.md, justfile
Adds the plugin workspace member and dependency wiring, new crate manifests, example plugin metadata, ignore rules, build and registration documentation, and clean-target updates.
ABI surface and runtime wrappers
crates/plugin/src/lib.rs
Defines the native ABI constants and types, host API table, plugin descriptor, runtime wrappers, scope guards, continuations, and scope-stack helpers.
Plugin context and callback plumbing
crates/plugin/src/lib.rs
Adds typed registration wrappers, callback trampolines, host string marshaling, plugin state, lifecycle trampolines, exported entry construction, and the entry macro.
Example plugin behavior
examples/rust-native-plugin/src/lib.rs
Adds config parsing, diagnostics, subscriber and interceptor registration, runtime mark/scope emission, request tagging, JSON tagging, and entrypoint registration.
Typed callback tests
crates/plugin/tests/typed_callbacks.rs
Adds the test harness, ABI assertions, mock host surface, helper utilities, typed callback cases, stream cases, registration cleanup, and panic handling checks.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Suggested labels

DO NOT MERGE

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.13% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits and accurately summarizes the native Rust plugin SDK work.
Description check ✅ Passed The description includes the required overview, details, reviewer start point, checklist, and related issues sections.
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:XXL PR is very large Feature a new feature lang:rust PR changes/introduces Rust code labels Jun 25, 2026
@github-actions

Copy link
Copy Markdown

@willkill07 willkill07 self-assigned this Jun 25, 2026
@willkill07 willkill07 added this to the 0.5 milestone Jun 25, 2026
@willkill07 willkill07 force-pushed the wkk_dynamic-plugin-2-native-sdk branch from 8048355 to 701970b Compare June 25, 2026 18:16
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

@willkill07 willkill07 force-pushed the wkk_dynamic-plugin-2-native-sdk branch from 701970b to 8f90864 Compare June 25, 2026 22:55
@github-actions github-actions Bot added size:XL PR is extra large and removed size:XXL PR is very large labels Jun 25, 2026
@willkill07 willkill07 marked this pull request as ready for review June 25, 2026 22:59
@willkill07 willkill07 requested a review from a team as a code owner June 25, 2026 22:59
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot added the DO NOT MERGE PR should not be merged; see PR for details label Jun 25, 2026

@afourniernv afourniernv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we should consider modularizing lib.rs / splitting it maybe at some point? Othewise LGTM.

@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: 9

🤖 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/plugin/src/lib.rs`:
- Around line 1797-1844: The typed_llm_request_intercept_trampoline callback is
publishing a partially written output pair when request serialization succeeds
but annotated serialization fails. Update this trampoline to preserve
all-or-nothing behavior by only assigning out_request_json and
out_annotated_json after both serializations succeed, or by cleaning up and
nulling the first output if the second write fails. Use
typed_llm_request_intercept_trampoline, write_json, and write_optional_json as
the key points to adjust the flow so no half-written host string is leaked on
error.
- Around line 2133-2141: The exported entrypoint generated by nemo_relay_plugin!
currently calls $constructor() through export_plugin without any panic boundary,
so a panic can abort the host. Update the macro’s extern "C" function to wrap
the full entry path in the same catch_unwind-based panic-to-status handling used
by the callback trampolines, and map any panic to NemoRelayStatus::Internal;
make sure this covers $constructor(), plugin_kind(), and
allows_multiple_components() through the existing export_plugin flow.
- Around line 2028-2041: The read_host_string helper is handling null and empty
inputs incorrectly: it currently maps a null value to an empty string and still
builds a slice from string_data() even when the pointer is null with zero
length. Update read_host_string in the plugin lib so a null handle returns None,
and add a len == 0 fast path before calling from_raw_parts; keep the existing
UTF-8 conversion for non-empty data and preserve the None result when
string_data() is null but len is positive.

In `@crates/plugin/tests/typed_callbacks.rs`:
- Around line 154-181: The fake host callbacks capture only the function
pointers and user data, so they do not verify that `PluginContext` is correctly
marshalling registration metadata. Update `capture_tool_request_intercept` and
`capture_tool_execution` to decode and store `name`, `priority`, and
`break_chain` in `RegisteredToolJson` and `RegisteredToolExecution`, then add
assertions in the corresponding registration tests to check those captured
values match what was passed through the API.
- Around line 595-646: The current test only verifies the success path for
ToolNext in typed_tool_execution_registration_calls_next and fake_tool_next, so
add coverage for failure handling too. Extend the typed execution trampoline
tests to simulate next.call returning a non-Ok NemoRelayStatus and to pass
malformed JSON through fake_tool_next, then assert the registration callback
surfaces the failure instead of swallowing it or mis-mapping the result. Keep
the new cases close to typed_tool_execution_registration_calls_next and reuse
ToolNext, fake_tool_next, and take_tool_execution_registration to locate the
behavior.
- Around line 63-74: The ABI test in typed_callbacks.rs only proves size
self-consistency because test_host().struct_size is derived from the same Rust
layout, so it can miss real C ABI breakage. Strengthen
native_abi_v1_struct_sizes_are_self_describing by asserting field offsets and
alignment for NemoRelayNativeHostApiV1 and NemoRelayNativePluginV1, or by
comparing the Rust layout against the generated C header/expected ABI layout, so
the test verifies actual layout compatibility rather than just matching
struct_size values.
- Around line 536-582: The error and panic paths in the typed callback test are
only checking status and LAST_ERROR, but they also need to verify that the
trampoline leaves out as null on failure. Update the assertions around the tool
registration callback in typed_callbacks.rs, using the existing registration.cb
invocation and out pointer setup, so both the callback failed and tool intercept
callback panicked paths confirm no output pointer is returned when
NemoRelayStatus::Internal is produced.

In `@examples/rust-native-plugin/relay-plugin.toml`:
- Around line 21-22: The checked-in relay manifest is macOS-specific because the
load.library value in relay-plugin.toml is hard-coded to a .dylib path with a
lib prefix. Update this manifest flow so it is portable across platforms by
using per-platform manifest variants or making the README explicitly instruct
users to edit the library path for Linux and Windows before activation, and keep
the relay-plugin.toml entry aligned with the actual platform-specific artifact
naming.

In `@examples/rust-native-plugin/src/lib.rs`:
- Around line 283-295: The `tag_json` helper is changing non-object `Json`
payloads into a new object shape in the `other` branch, which breaks valid
array/scalar `LlmRequest.content` values. Update `tag_json` so it only adds the
tag fields when the value is a `Json::Object`, and otherwise preserves the
original `Json` payload unchanged while still allowing the live tool/LLM
intercept callers to distinguish tagged objects via `tag_json`.
🪄 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: 0c04bd6c-7411-440a-a295-86cd829918f6

📥 Commits

Reviewing files that changed from the base of the PR and between ec47688 and 8f90864.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • Cargo.toml
  • crates/plugin/Cargo.toml
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • examples/rust-native-plugin/.gitignore
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.rs
  • justfile
📜 Review details
⏰ Context from checks skipped due to timeout. (20)
  • GitHub Check: WebAssembly / Test (windows-arm64)
  • GitHub Check: Node.js / Test (macos-arm64)
  • GitHub Check: WebAssembly / Test (windows-amd64)
  • GitHub Check: WebAssembly / Test (linux-arm64)
  • GitHub Check: Node.js / Test (windows-arm64)
  • GitHub Check: Node.js / Test (windows-amd64)
  • GitHub Check: WebAssembly / Test (linux-amd64)
  • GitHub Check: Rust / Test (windows-amd64)
  • GitHub Check: WebAssembly / Test (macos-arm64)
  • GitHub Check: Python / Test (macos-arm64)
  • GitHub Check: Rust / Test (windows-arm64)
  • GitHub Check: Node.js / Test (linux-arm64)
  • GitHub Check: Python / Test (windows-amd64)
  • GitHub Check: Rust / Test (macos-arm64)
  • GitHub Check: Rust / Test (linux-amd64)
  • GitHub Check: Python / Test (windows-arm64)
  • GitHub Check: Rust / Test (linux-arm64)
  • GitHub Check: Go / Test (windows-arm64)
  • GitHub Check: Go / Test (windows-amd64)
  • GitHub Check: License Diff / Run
🧰 Additional context used
📓 Path-based instructions (26)
**/*.{rs,toml}

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

Update Rust crate names and module prefixes during coordinated rename operations

Files:

  • examples/rust-native-plugin/relay-plugin.toml
  • Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.rs
**/*.{py,txt,toml,cfg,yaml,yml}

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

Update Python package names and top-level module imports during coordinated rename operations

Files:

  • examples/rust-native-plugin/relay-plugin.toml
  • Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
{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/relay-plugin.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/src/lib.rs
**/*.{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/relay-plugin.toml
  • Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
**/*.toml

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in TOML configuration files using hash comment syntax

Files:

  • examples/rust-native-plugin/relay-plugin.toml
  • Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
**/*.{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:

  • examples/rust-native-plugin/relay-plugin.toml
  • Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • examples/rust-native-plugin/relay-plugin.toml
  • Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • justfile
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.rs
**/Cargo.toml

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

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

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

**/Cargo.toml: Maintain Cargo.toml [workspace.package].version as the source of truth for the Rust workspace and Python build versioning
Keep Cargo.toml [workspace.dependencies] self-references aligned with the workspace version when the workspace version changes
After updating workspace package entries, run cargo check --workspace to refresh Cargo.lock

Files:

  • Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}

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

Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes

Files:

  • Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
**/*.{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
**/*.{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
justfile

📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)

justfile: Keep helper function inputs aligned when editing version helpers: set_project_version should call Cargo, Node, and coding-agent plugin version helpers for the same target version
Ensure set_cargo_workspace_version helper updates [workspace.package].version plus all workspace.dependencies references (nemo-relay, nemo-relay-adaptive, nemo-relay-pii-redaction, nemo-relay-ffi, nemo-relay-cli)
Ensure set_node_package_versions helper updates crates/node/package.json, integrations/openclaw/package.json, corresponding package-lock.json entries, and OpenClaw nemo-relay-node dependency entries

Files:

  • justfile
{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}

⚙️ CodeRabbit configuration file

{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}: Review automation changes for reproducibility, pinned versions where appropriate, secret handling, and consistency with the documented validation matrix.
Pay attention to commands that need generated native artifacts, FFI libraries, or platform-specific environment variables.

Files:

  • justfile
**/*.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/plugin/tests/typed_callbacks.rs
🪛 LanguageTool
examples/rust-native-plugin/README.md

[style] ~72-~72: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...tion guardrails controlled by config. - Tool request and execution intercepts that m...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (5)
crates/plugin/tests/typed_callbacks.rs (1)

1-1: 📐 Maintainability & Code Quality

Confirm the required Rust validation commands.

This Rust change needs the repository-required Rust checks, but the PR objective only mentions package-scoped cargo test plus cargo check -p nemo-relay-cli. Please confirm just test-rust, cargo fmt --all, and cargo clippy --workspace --all-targets -- -D warnings were run.

As per coding guidelines, **/*.rs: “Any Rust change must run just test-rust,” “Any Rust change must run cargo fmt --all,” and “Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings.”

Source: Coding guidelines

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

1-5: 📐 Maintainability & Code Quality

Run the full Rust validation matrix before merge. Include cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings, and just test-rust in the PR results.

examples/rust-native-plugin/Cargo.toml (1)

1-19: LGTM!

examples/rust-native-plugin/.gitignore (1)

1-5: LGTM!

justfile (1)

847-848: LGTM!

Comment thread crates/plugin/src/lib.rs
Comment thread crates/plugin/src/lib.rs Outdated
Comment thread crates/plugin/src/lib.rs
Comment thread crates/plugin/tests/typed_callbacks.rs
Comment thread crates/plugin/tests/typed_callbacks.rs
Comment thread crates/plugin/tests/typed_callbacks.rs
Comment thread crates/plugin/tests/typed_callbacks.rs
Comment thread examples/rust-native-plugin/relay-plugin.toml Outdated
Comment thread examples/rust-native-plugin/src/lib.rs
@willkill07 willkill07 removed the DO NOT MERGE PR should not be merged; see PR for details label Jun 25, 2026
@willkill07 willkill07 force-pushed the wkk_dynamic-plugin-2-native-sdk branch from 8f90864 to 0dd53de Compare June 25, 2026 23:40
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

@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

🤖 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/plugin/src/lib.rs`:
- Around line 1499-1508: The with_name helper is collapsing every
HostString::new failure into NemoRelayStatus::InvalidUtf8 even though the input
is already a Rust &str, so the real host allocation status is being lost. Update
with_name and the raw registration helpers that call it to propagate the actual
NemoRelayStatus returned by HostString::new/string_new instead of rewriting it,
while still passing the allocated pointer to the callback only on success.
- Around line 1950-2005: `PluginState<P>` is accessed mutably from both
`validate_trampoline` and `register_trampoline` through the shared `user_data`
ABI pointer without synchronization. Update the exported state handling in
`export_plugin` so the shared `PluginState<P>` is protected by a mutex, then
acquire that lock inside both trampolines before calling `validate` or
`register`. Map any lock poisoning or lock acquisition failure to
`NemoRelayStatus::Internal`, and keep the existing
`read_json_object`/`write_json` and `set_last_error` flow unchanged.

In `@crates/plugin/tests/typed_callbacks.rs`:
- Around line 64-69: The LLM intercept test helper currently ignores
registration metadata, so the test can miss bugs in
PluginContext::register_llm_request_intercept marshalling. Update
capture_llm_request_intercept and the
typed_llm_request_intercept_does_not_publish_partial_outputs test to mirror the
tool-registration assertions by recording and checking name, priority, and
break_chain alongside the callback fields. Ensure the captured registration
metadata is asserted where the intercept is registered so the test fails if any
of those fields are passed incorrectly.

In `@examples/rust-native-plugin/README.md`:
- Around line 39-41: The plugin activation example uses a
working-directory-dependent manifest path in the `nemo-relay plugins add`
command, which makes the snippet not copy/paste safe. Update the example around
`examples/rust-native-plugin/README.md` so the working directory is explicit or
both commands use the same path style, and keep the `nemo-relay plugins add` and
`nemo-relay plugins enable` flow consistent with the manifest reference used
later in the README.
- Around line 46-55: The TOML example under the rust-native-plugin README uses
an invalid multiline inline table for `plugins.dynamic.config`, so update the
example to use a valid TOML structure in the `[[plugins.dynamic]]` block by
switching to a nested `[plugins.dynamic.config]` table or keeping the inline
table on one line. Keep the `manifest` and `config` fields in the example
aligned with the `plugins.dynamic`/`config` symbols so the snippet can be copied
directly into `plugins.toml` without parse errors.
🪄 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: 397b8beb-6b10-4153-881d-08e90279efa0

📥 Commits

Reviewing files that changed from the base of the PR and between 8f90864 and 0dd53de.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • Cargo.toml
  • crates/plugin/Cargo.toml
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • examples/rust-native-plugin/.gitignore
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.rs
  • justfile
📜 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)
**/{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:

  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.rs
**/*.{rs,toml}

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

Update Rust crate names and module prefixes during coordinated rename operations

Files:

  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.rs
**/*.{py,txt,toml,cfg,yaml,yml}

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

Update Python package names and top-level module imports during coordinated rename operations

Files:

  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
**/Cargo.toml

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

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

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

**/Cargo.toml: Maintain Cargo.toml [workspace.package].version as the source of truth for the Rust workspace and Python build versioning
Keep Cargo.toml [workspace.dependencies] self-references aligned with the workspace version when the workspace version changes
After updating workspace package entries, run cargo check --workspace to refresh Cargo.lock

Files:

  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}

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

Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes

Files:

  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • 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:

  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/relay-plugin.toml
**/*.toml

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in TOML configuration files using hash comment syntax

Files:

  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
**/*.{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:

  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • Cargo.toml
  • crates/plugin/Cargo.toml
  • justfile
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.rs
justfile

📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)

justfile: Keep helper function inputs aligned when editing version helpers: set_project_version should call Cargo, Node, and coding-agent plugin version helpers for the same target version
Ensure set_cargo_workspace_version helper updates [workspace.package].version plus all workspace.dependencies references (nemo-relay, nemo-relay-adaptive, nemo-relay-pii-redaction, nemo-relay-ffi, nemo-relay-cli)
Ensure set_node_package_versions helper updates crates/node/package.json, integrations/openclaw/package.json, corresponding package-lock.json entries, and OpenClaw nemo-relay-node dependency entries

Files:

  • justfile
{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}

⚙️ CodeRabbit configuration file

{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}: Review automation changes for reproducibility, pinned versions where appropriate, secret handling, and consistency with the documented validation matrix.
Pay attention to commands that need generated native artifacts, FFI libraries, or platform-specific environment variables.

Files:

  • justfile
{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/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.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
**/*.{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
**/*.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/plugin/tests/typed_callbacks.rs
🔇 Additional comments (1)
crates/plugin/Cargo.toml (1)

4-19: 📐 Maintainability & Code Quality

Please run the full Rust validation matrix for this new crate.

The PR notes targeted cargo test and cargo check runs, but repo policy for any Rust change requires just test-rust, cargo fmt --all, and cargo clippy --workspace --all-targets -- -D warnings before merge. As per coding guidelines, **/*.rs: "Any Rust change must run just test-rust", "cargo fmt --all", and "cargo clippy --workspace --all-targets -- -D warnings."

Source: Coding guidelines

Comment thread crates/plugin/src/lib.rs
Comment thread crates/plugin/src/lib.rs
Comment thread crates/plugin/tests/typed_callbacks.rs Outdated
Comment thread examples/rust-native-plugin/README.md
Comment thread examples/rust-native-plugin/README.md
@willkill07 willkill07 force-pushed the wkk_dynamic-plugin-2-native-sdk branch from 0dd53de to 55d7c57 Compare June 26, 2026 00:19
@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown

@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: 6

🤖 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/plugin/src/lib.rs`:
- Around line 670-680: `ToolNext::call` and `LlmNext::call` should not assume a
non-null output pointer when `next_fn` returns `NemoRelayStatus::Ok`; add an
explicit null check on `out` before calling `read_json_value` or `string_free`.
If `out` is null, return a clear SDK error instead of continuing, and only free
the string after confirming it is valid so the FFI path cannot crash on a broken
continuation contract.
- Around line 1976-2000: Panic recovery in the native plugin trampolines is
returning NemoRelayStatus::Internal without updating the host error, so a
previous last_error can leak through. In validate_trampoline,
register_trampoline, and the exported entry path, handle the catch_unwind
failure by setting a fresh host error before returning Internal, using the same
error-reporting flow as callback_panic so the host always receives a new
diagnostic after a panic.

In `@crates/plugin/tests/typed_callbacks.rs`:
- Around line 1116-1129: The panic-entry tests only assert the returned Internal
status and reuse one plugin instance, so they miss cases where an entrypoint
partially mutates exported state before panicking. Update the typed callback
tests around constructor_panic_entry, plugin_kind_panic_entry, and
allows_multiple_panic_entry to use a fresh NemoRelayNativePluginV1::default()
for each call and explicitly verify that ownership-related fields such as
user_data, callbacks, and plugin_kind remain unset after the panic path.
- Around line 1016-1051: Add a typed test case for name-allocation failure in
register_tool_request_intercept, mirroring the raw-path coverage already
present. The new test should force String::new/name allocation to fail before
host registration, then assert the typed registration returns the allocation
error and that the captured callback state is dropped (e.g. via DropCounter), so
the boxed closure does not leak when user_data is never handed to the host.

In `@examples/rust-native-plugin/README.md`:
- Around line 63-73: The list under the “What the Example Registers” heading
starts immediately without a complete introductory sentence. Add a short lead-in
sentence before the bullet list in the README section so the list is introduced
by a full sentence, keeping the existing bullet items and wording intact.

In `@examples/rust-native-plugin/src/lib.rs`:
- Around line 145-153: The example is manually balancing scope lifecycle with
push_scope and pop_scope, which should be replaced with the SDK scope guard
helper. Update the native plugin flow around the runtime scope handling to use
the new guard-based API instead of explicitly calling push_scope/pop_scope, and
apply the same change in the other referenced scope block so the example
demonstrates the safer authoring-layer pattern using runtime and the
scope-related helper symbols consistently.
🪄 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: d64575ce-22bf-433c-8bbc-a7984869ce04

📥 Commits

Reviewing files that changed from the base of the PR and between 0dd53de and 55d7c57.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • Cargo.toml
  • crates/plugin/Cargo.toml
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • examples/rust-native-plugin/.gitignore
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.rs
  • justfile
📜 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)
**/{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/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.rs
**/*.{py,txt,toml,cfg,yaml,yml}

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

Update Python package names and top-level module imports during coordinated rename operations

Files:

  • crates/plugin/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/Cargo.toml
**/Cargo.toml

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

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

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

**/Cargo.toml: Maintain Cargo.toml [workspace.package].version as the source of truth for the Rust workspace and Python build versioning
Keep Cargo.toml [workspace.dependencies] self-references aligned with the workspace version when the workspace version changes
After updating workspace package entries, run cargo check --workspace to refresh Cargo.lock

Files:

  • crates/plugin/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}

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

Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes

Files:

  • crates/plugin/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • 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:

  • crates/plugin/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
**/*.toml

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in TOML configuration files using hash comment syntax

Files:

  • crates/plugin/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/Cargo.toml
**/*.{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/plugin/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/plugin/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/Cargo.toml
  • justfile
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/relay-plugin.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/src/lib.rs
justfile

📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)

justfile: Keep helper function inputs aligned when editing version helpers: set_project_version should call Cargo, Node, and coding-agent plugin version helpers for the same target version
Ensure set_cargo_workspace_version helper updates [workspace.package].version plus all workspace.dependencies references (nemo-relay, nemo-relay-adaptive, nemo-relay-pii-redaction, nemo-relay-ffi, nemo-relay-cli)
Ensure set_node_package_versions helper updates crates/node/package.json, integrations/openclaw/package.json, corresponding package-lock.json entries, and OpenClaw nemo-relay-node dependency entries

Files:

  • justfile
{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}

⚙️ CodeRabbit configuration file

{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}: Review automation changes for reproducibility, pinned versions where appropriate, secret handling, and consistency with the documented validation matrix.
Pay attention to commands that need generated native artifacts, FFI libraries, or platform-specific environment variables.

Files:

  • justfile
**/*.{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
**/*.{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
**/*.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/plugin/tests/typed_callbacks.rs
🔇 Additional comments (5)
crates/plugin/tests/typed_callbacks.rs (1)

1-1130: 📐 Maintainability & Code Quality

Confirm the required Rust validation matrix ran.

The PR objectives list targeted cargo test and cargo check commands, but this Rust change also needs confirmation for just test-rust, cargo fmt --all, and cargo clippy --workspace --all-targets -- -D warnings.

As per coding guidelines, **/*.rs: “Any Rust change must run just test-rust”, “Any Rust change must run cargo fmt --all”, and “Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings”.

Source: Coding guidelines

Cargo.toml (1)

8-8: 📐 Maintainability & Code Quality

Confirm the workspace-wide Cargo refresh.

Adding crates/plugin to members and [workspace.dependencies] changes the workspace graph, but the PR summary only shows package-scoped cargo test/cargo check runs. Please confirm cargo check --workspace was run so the new member/dependency wiring is validated against the full resolver state and Cargo.lock. As per coding guidelines, After updating workspace package entries, run cargo check --workspace to refresh Cargo.lock.

Also applies to: 30-30

Source: Coding guidelines

crates/plugin/Cargo.toml (1)

1-19: LGTM!

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

1-17: 📐 Maintainability & Code Quality

Confirm the required Rust validation matrix ran.

The PR summary lists targeted crate-level cargo test / cargo check commands, but this new Rust surface should also have the repo-standard just test-rust, cargo fmt --all, cargo clippy --workspace --all-targets -- -D warnings, and uv run pre-commit run --all-files checks before merge. As per coding guidelines, Any Rust change must run just test-rust, cargo fmt --all, cargo clippy --workspace --all-targets -- -D warnings, and Validate Rust code with uv run pre-commit run --all-files.

Source: Coding guidelines

examples/rust-native-plugin/src/lib.rs (1)

1-294: 📐 Maintainability & Code Quality

Please include the full Rust validation matrix for this new crate.

The PR notes targeted package tests, but repo policy for any Rust change also expects just test-rust, cargo fmt --all, and cargo clippy --workspace --all-targets -- -D warnings before merge. As per coding guidelines, any Rust change must run just test-rust, cargo fmt --all, and cargo clippy --workspace --all-targets -- -D warnings.

Source: Coding guidelines

Comment thread crates/plugin/src/lib.rs
Comment thread crates/plugin/src/lib.rs Outdated
Comment thread crates/plugin/tests/typed_callbacks.rs
Comment thread crates/plugin/tests/typed_callbacks.rs Outdated
Comment thread examples/rust-native-plugin/README.md
Comment thread examples/rust-native-plugin/src/lib.rs Outdated
@willkill07 willkill07 force-pushed the wkk_dynamic-plugin-2-native-sdk branch from 55d7c57 to 9329e6a Compare June 26, 2026 00:45
@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown

@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: 3

🤖 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/plugin/src/lib.rs`:
- Around line 1594-1906: The typed callback trampolines leave out-parameters
unchanged on early failure, which can leak stale values across the C ABI
boundary. Update the entry path in the relevant trampolines such as
typed_tool_sanitize_trampoline, typed_tool_intercept_trampoline,
typed_tool_conditional_trampoline, typed_tool_execution_trampoline,
typed_llm_sanitize_request_trampoline, typed_llm_sanitize_response_trampoline,
typed_llm_conditional_trampoline, typed_llm_request_intercept_trampoline, and
typed_llm_execution_trampoline to clear each out_* pointer immediately after the
null-pointer check and before any fallible read/callback work, so failures
always leave outputs null.
- Around line 1608-1609: The current `read_host_string` call sites are
collapsing both null ABI inputs and malformed UTF-8 into
`NemoRelayStatus::InvalidUtf8`, which misclassifies null pointers; update the
affected `plugin::lib` handlers to distinguish a null
`name`/`request_json`/`payload_json` from invalid encoding and return
`NemoRelayStatus::NullPointer` for null handles while keeping `InvalidUtf8` only
for malformed strings. Apply this in the relevant request-parsing paths that use
`read_host_string` before `read_json_value`, including the `name`/`payload_json`
and similar argument extraction sites listed in the review, so each ABI
violation surfaces the correct failure class.

In `@crates/plugin/tests/typed_callbacks.rs`:
- Around line 1075-1118: Add the missing failure-path coverage for LlmNext::call
in typed_callbacks.rs by mirroring the ToolNext::call tests for non-Ok relay
status and invalid JSON output, alongside the existing null-output case. Update
the typed_llm_execution_surfaces_null_next_output test area (and any nearby
LlmNext-focused helpers) to assert the same error mapping behavior, status
propagation, and LAST_ERROR handling as ToolNext so regressions in LLM
continuation paths are caught.
🪄 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: 6506f5ed-0300-4cc3-b295-b8ce2fe569ee

📥 Commits

Reviewing files that changed from the base of the PR and between 55d7c57 and 9329e6a.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • Cargo.toml
  • crates/plugin/Cargo.toml
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • examples/rust-native-plugin/.gitignore
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.rs
  • justfile
📜 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)
justfile

📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)

justfile: Keep helper function inputs aligned when editing version helpers: set_project_version should call Cargo, Node, and coding-agent plugin version helpers for the same target version
Ensure set_cargo_workspace_version helper updates [workspace.package].version plus all workspace.dependencies references (nemo-relay, nemo-relay-adaptive, nemo-relay-pii-redaction, nemo-relay-ffi, nemo-relay-cli)
Ensure set_node_package_versions helper updates crates/node/package.json, integrations/openclaw/package.json, corresponding package-lock.json entries, and OpenClaw nemo-relay-node dependency entries

Files:

  • justfile
**

⚙️ 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:

  • justfile
  • examples/rust-native-plugin/relay-plugin.toml
  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.rs
{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}

⚙️ CodeRabbit configuration file

{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}: Review automation changes for reproducibility, pinned versions where appropriate, secret handling, and consistency with the documented validation matrix.
Pay attention to commands that need generated native artifacts, FFI libraries, or platform-specific environment variables.

Files:

  • justfile
**/*.{rs,toml}

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

Update Rust crate names and module prefixes during coordinated rename operations

Files:

  • examples/rust-native-plugin/relay-plugin.toml
  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.rs
**/*.{py,txt,toml,cfg,yaml,yml}

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

Update Python package names and top-level module imports during coordinated rename operations

Files:

  • examples/rust-native-plugin/relay-plugin.toml
  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
{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/relay-plugin.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/src/lib.rs
**/*.{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/relay-plugin.toml
  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
**/*.toml

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in TOML configuration files using hash comment syntax

Files:

  • examples/rust-native-plugin/relay-plugin.toml
  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
**/*.{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:

  • examples/rust-native-plugin/relay-plugin.toml
  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.rs
**/Cargo.toml

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

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

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

**/Cargo.toml: Maintain Cargo.toml [workspace.package].version as the source of truth for the Rust workspace and Python build versioning
Keep Cargo.toml [workspace.dependencies] self-references aligned with the workspace version when the workspace version changes
After updating workspace package entries, run cargo check --workspace to refresh Cargo.lock

Files:

  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}

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

Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes

Files:

  • Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
**/*.{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
**/*.{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
**/*.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/plugin/tests/typed_callbacks.rs
🔇 Additional comments (6)
examples/rust-native-plugin/Cargo.toml (1)

1-19: LGTM!

examples/rust-native-plugin/relay-plugin.toml (1)

1-24: LGTM!

examples/rust-native-plugin/.gitignore (1)

1-5: LGTM!

justfile (1)

817-848: LGTM!

examples/rust-native-plugin/README.md (1)

1-78: LGTM!

examples/rust-native-plugin/src/lib.rs (1)

1-295: 📐 Maintainability & Code Quality

Add the required Rust validation results before merge.

Include just test-rust, cargo fmt --all, and cargo clippy --workspace --all-targets -- -D warnings for this Rust change.

Comment thread crates/plugin/src/lib.rs
Comment thread crates/plugin/src/lib.rs Outdated
Comment thread crates/plugin/tests/typed_callbacks.rs
Signed-off-by: Will Killian <wkillian@nvidia.com>
@willkill07 willkill07 force-pushed the wkk_dynamic-plugin-2-native-sdk branch from 9329e6a to 93e5b53 Compare June 26, 2026 02:28
@github-actions github-actions Bot added size:XXL PR is very large and removed size:XL PR is extra large labels Jun 26, 2026
@github-actions

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 (344 packages)
[license-diff] current: generating Node inventory
[license-diff] current: Node inventory complete (364 packages)
[license-diff] current: generating Python inventory
[license-diff] current: Python inventory complete (104 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 (344 packages)
[license-diff] base: generating Node inventory
[license-diff] base: Node inventory complete (364 packages)
[license-diff] base: generating Python inventory
[license-diff] base: Python inventory complete (104 packages)
[license-diff] base inventory complete
[license-diff] removing temporary base worktree
[license-diff] comparing inventories
[license-diff] rendering Markdown output
[license-diff] done

@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: 6

🤖 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/plugin/src/lib.rs`:
- Around line 1829-1832: Wrap the C-ABI destructor paths in `catch_unwind` so
panics during user-owned `Drop` do not unwind across `extern "C"`. Update
`drop_typed_callback`, `drop_typed_llm_json_stream`, and `drop_plugin_state` in
the plugin runtime to catch any panic from `Box::from_raw`/drop and convert it
into `set_last_error(...)` instead of letting it escape. Keep the existing null
checks and ensure the error path records a useful message while the success path
still frees the boxed state normally.
- Around line 793-799: The raw LLM stream cleanup path in LlmStream::from_raw is
leaking host-owned user_data when validation fails on struct_size or a null next
callback. Update the from_raw construction flow in crates/plugin/src/lib.rs to
dispose of the incoming NemoRelayNativeLlmStreamV1 via its drop callback before
returning any error from those early checks, while preserving the existing
success path that wraps the raw stream after validation.
- Around line 2633-2648: Move the plugin constructor work behind the
`host`/`out` validation in `export_plugin()` so invalid pointers return before
any constructor side effects run. Also clear `*out` to
`NemoRelayNativePluginV1::default()` immediately after the null check and before
any ABI/version/allocation failures, so callers never see stale plugin data. Use
the existing `export_plugin`, `plugin.plugin_kind()`, and `HostString::new` flow
to keep the constructor-dependent setup after the early checks.

In `@crates/plugin/tests/typed_callbacks.rs`:
- Around line 1578-1580: The typed stream wrapper is only being verified on the
first chunk, so this test can miss later chunks bypassing the wrapper; update
the streamed chunk assertions in the typed callbacks test to also validate the
second chunk includes the expected wrapped shape using the existing
poll_stream_chunk flow and the chunk result, so the behavior promised by the
callback mapping is covered consistently across all emitted chunks.
- Around line 1623-1635: The failing-stream test only verifies that
NemoRelayNativeLlmStreamV1::next is unset, but the ABI contract also requires
the whole output struct to remain uninitialized on Internal. Tighten the
typed_callbacks.rs test around the registration.cb invocation by asserting that
NemoRelayNativeLlmStreamV1 fields such as user_data, cancel, and drop are also
still None after failing_llm_stream_next returns failure, so the regression is
covered for the full output state.

In `@examples/rust-native-plugin/src/lib.rs`:
- Line 72: The config field list is duplicated across ExampleConfig, parse, and
known_fields, which can drift and cause false unknown-field warnings. Update the
logic around known_fields in lib.rs so it is derived from a single source of
truth used by ExampleConfig and parse, rather than being maintained as a
hardcoded list. Keep the field names in one shared definition or generated from
the config representation, and ensure the warning check uses that shared set.
🪄 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: 10a7d433-e5aa-44a2-bb26-371e3e47379e

📥 Commits

Reviewing files that changed from the base of the PR and between 9329e6a and 93e5b53.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • Cargo.toml
  • crates/plugin/Cargo.toml
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • examples/rust-native-plugin/.gitignore
  • examples/rust-native-plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.rs
  • justfile
📜 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)
**/{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:

  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.rs
**/*.{rs,toml}

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

Update Rust crate names and module prefixes during coordinated rename operations

Files:

  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.rs
**/*.{py,txt,toml,cfg,yaml,yml}

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

Update Python package names and top-level module imports during coordinated rename operations

Files:

  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
**/Cargo.toml

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

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

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

**/Cargo.toml: Maintain Cargo.toml [workspace.package].version as the source of truth for the Rust workspace and Python build versioning
Keep Cargo.toml [workspace.dependencies] self-references aligned with the workspace version when the workspace version changes
After updating workspace package entries, run cargo check --workspace to refresh Cargo.lock

Files:

  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • Cargo.toml
{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/Cargo.toml
  • examples/rust-native-plugin/README.md
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.rs
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}

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

Ensure renamed public surfaces are reflected consistently in manifests and docs for large or public-facing changes

Files:

  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • Cargo.toml
**/*.{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/Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
**/*.toml

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in TOML configuration files using hash comment syntax

Files:

  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
**/*.{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:

  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • examples/rust-native-plugin/Cargo.toml
  • crates/plugin/Cargo.toml
  • examples/rust-native-plugin/README.md
  • justfile
  • Cargo.toml
  • examples/rust-native-plugin/relay-plugin.toml
  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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
**/*.{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
justfile

📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)

justfile: Keep helper function inputs aligned when editing version helpers: set_project_version should call Cargo, Node, and coding-agent plugin version helpers for the same target version
Ensure set_cargo_workspace_version helper updates [workspace.package].version plus all workspace.dependencies references (nemo-relay, nemo-relay-adaptive, nemo-relay-pii-redaction, nemo-relay-ffi, nemo-relay-cli)
Ensure set_node_package_versions helper updates crates/node/package.json, integrations/openclaw/package.json, corresponding package-lock.json entries, and OpenClaw nemo-relay-node dependency entries

Files:

  • justfile
{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}

⚙️ CodeRabbit configuration file

{.github/**,.gitlab-ci.yml,.pre-commit-config.yaml,justfile,scripts/**}: Review automation changes for reproducibility, pinned versions where appropriate, secret handling, and consistency with the documented validation matrix.
Pay attention to commands that need generated native artifacts, FFI libraries, or platform-specific environment variables.

Files:

  • justfile
**/*.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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:

  • examples/rust-native-plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/tests/typed_callbacks.rs
  • crates/plugin/src/lib.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/plugin/tests/typed_callbacks.rs
🔇 Additional comments (13)
examples/rust-native-plugin/src/lib.rs (5)

1-59: LGTM!


111-214: LGTM!


216-229: LGTM!


243-294: LGTM!


231-241: 🩺 Stability & Availability

No deadlock path here. Native subscriber delivery is queued to a dispatcher thread, and event emission snapshots subscribers before releasing the runtime lock, so emit_mark can be called from a subscriber without reentering a held non-reentrant lock.

			> Likely an incorrect or invalid review comment.
Cargo.toml (1)

8-8: LGTM!

Also applies to: 30-30

crates/plugin/Cargo.toml (1)

1-19: LGTM!

examples/rust-native-plugin/Cargo.toml (1)

1-20: LGTM!

examples/rust-native-plugin/.gitignore (1)

1-5: LGTM!

examples/rust-native-plugin/README.md (1)

1-78: LGTM!

justfile (1)

847-848: LGTM!

examples/rust-native-plugin/relay-plugin.toml (1)

20-23: 🎯 Functional Correctness

Resolve load.library relative to the manifest directory (or make it absolute). The README adds ./examples/rust-native-plugin/relay-plugin.toml from the repo root, but the manifest keeps target/debug/... as a relative path. If native loading uses that string as-is, the example only works from one working directory.

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

1-2: 📐 Maintainability & Code Quality

Confirm the required Rust validation commands before merge.

The PR validation list does not mention the repo-required full Rust checks. Please confirm just test-rust, cargo fmt --all, and cargo clippy --workspace --all-targets -- -D warnings were run for this Rust SDK change. As per coding guidelines, “Any Rust change must run just test-rust”, “Any Rust change must run cargo fmt --all”, and “Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings”.

Source: Coding guidelines

Comment thread crates/plugin/src/lib.rs
Comment on lines +793 to +799
let mut raw = NemoRelayNativeLlmStreamV1::default();
let status = unsafe { (self.next_fn)(request.as_ptr(), self.next_ctx, &mut raw) };
if status != NemoRelayStatus::Ok {
return Err(format!("llm stream next failed: {status:?}"));
}
unsafe { LlmStream::from_raw(self.host, raw) }
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail
git ls-files crates/plugin/src/lib.rs crates/plugin/src
wc -l crates/plugin/src/lib.rs
rg -n "from_raw|drop_raw_llm_stream|LlmStreamNext::call|NemoRelayNativeLlmStreamV1" crates/plugin/src/lib.rs
sed -n '760,860p' crates/plugin/src/lib.rs

Repository: NVIDIA/NeMo-Relay

Length of output: 5291


🏁 Script executed:

set -euo pipefail
git ls-files crates/plugin/src/lib.rs crates/plugin/src
wc -l crates/plugin/src/lib.rs
rg -n "from_raw|drop_raw_llm_stream|LlmStreamNext::call|NemoRelayNativeLlmStreamV1" crates/plugin/src/lib.rs
sed -n '760,860p' crates/plugin/src/lib.rs

Repository: NVIDIA/NeMo-Relay

Length of output: 5291


🏁 Script executed:

set -euo pipefail
sed -n '140,240p' crates/plugin/src/lib.rs
sed -n '2200,2365p' crates/plugin/src/lib.rs
sed -n '2365,2465p' crates/plugin/src/lib.rs

Repository: NVIDIA/NeMo-Relay

Length of output: 12791


🏁 Script executed:

sed -n '140,240p' crates/plugin/src/lib.rs
sed -n '2200,2365p' crates/plugin/src/lib.rs
sed -n '2365,2465p' crates/plugin/src/lib.rs

Repository: NVIDIA/NeMo-Relay

Length of output: 12791


🏁 Script executed:

set -euo pipefail
rg -n "impl Drop for LlmStream|drop_fn|user_data|struct NemoRelayNativeLlmStreamV1|type .*LlmStreamNextFn|NemoRelayNativeLlmStreamNextFn" crates/plugin/src/lib.rs
sed -n '150,210p' crates/plugin/src/lib.rs
sed -n '2228,2345p' crates/plugin/src/lib.rs
sed -n '810,910p' crates/plugin/src/lib.rs

Repository: NVIDIA/NeMo-Relay

Length of output: 20963


🏁 Script executed:

set -euo pipefail
rg -n "impl Drop for LlmStream|drop_fn|user_data|struct NemoRelayNativeLlmStreamV1|type .*LlmStreamNextFn|NemoRelayNativeLlmStreamNextFn" crates/plugin/src/lib.rs
sed -n '150,210p' crates/plugin/src/lib.rs
sed -n '2228,2345p' crates/plugin/src/lib.rs
sed -n '810,910p' crates/plugin/src/lib.rs

Repository: NVIDIA/NeMo-Relay

Length of output: 20963


Free rejected raw LLM streams. In crates/plugin/src/lib.rs:818-830, LlmStream::from_raw returns early on invalid struct_size or a null next callback without invoking the raw stream’s drop callback, so a host-owned user_data can leak. Clean up the raw table before returning the error.

🤖 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/src/lib.rs` around lines 793 - 799, The raw LLM stream cleanup
path in LlmStream::from_raw is leaking host-owned user_data when validation
fails on struct_size or a null next callback. Update the from_raw construction
flow in crates/plugin/src/lib.rs to dispose of the incoming
NemoRelayNativeLlmStreamV1 via its drop callback before returning any error from
those early checks, while preserving the existing success path that wraps the
raw stream after validation.

Comment thread crates/plugin/src/lib.rs
Comment on lines +1829 to +1832
unsafe extern "C" fn drop_typed_callback<F>(user_data: *mut c_void) {
if !user_data.is_null() {
drop(unsafe { Box::from_raw(user_data as *mut TypedCallback<F>) });
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Inspect the relevant Rust file and all extern "C" destructors around the cited ranges.
sed -n '1780,1865p' crates/plugin/src/lib.rs
printf '\n----\n'
sed -n '2280,2335p' crates/plugin/src/lib.rs
printf '\n----\n'
sed -n '2390,2455p' crates/plugin/src/lib.rs

Repository: NVIDIA/NeMo-Relay

Length of output: 6935


🏁 Script executed:

# Find all extern "C" drop/cleanup functions in the plugin crate.
rg -n 'unsafe extern "C" fn drop_|extern "C" fn drop_|catch_unwind|set_last_error' crates/plugin/src/lib.rs

Repository: NVIDIA/NeMo-Relay

Length of output: 3148


🏁 Script executed:

# Check whether any other extern "C" drop/destructor-style functions exist in this crate.
rg -n 'unsafe extern "C" fn .*drop|unsafe extern "C" fn .*free|unsafe extern "C" fn .*destroy' crates/plugin/src/lib.rs

Repository: NVIDIA/NeMo-Relay

Length of output: 396


Wrap the C-ABI destructors in catch_unwind.

drop_typed_callback, drop_typed_llm_json_stream, and drop_plugin_state can unwind through extern "C" if user-owned state panics during Drop, which can abort the host. Convert that to set_last_error(...) instead of letting the unwind escape.

🤖 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/src/lib.rs` around lines 1829 - 1832, Wrap the C-ABI destructor
paths in `catch_unwind` so panics during user-owned `Drop` do not unwind across
`extern "C"`. Update `drop_typed_callback`, `drop_typed_llm_json_stream`, and
`drop_plugin_state` in the plugin runtime to catch any panic from
`Box::from_raw`/drop and convert it into `set_last_error(...)` instead of
letting it escape. Keep the existing null checks and ensure the error path
records a useful message while the success path still frees the boxed state
normally.

Comment thread crates/plugin/src/lib.rs
Comment on lines +2633 to +2648
if host.is_null() || out.is_null() {
return NemoRelayStatus::NullPointer;
}
let host_ref = unsafe { &*host };
if host_ref.abi_version != NEMO_RELAY_NATIVE_ABI_VERSION {
return NemoRelayStatus::InvalidArg;
}
if host_ref.struct_size < std::mem::size_of::<NemoRelayNativeHostApiV1>() {
return NemoRelayStatus::InvalidArg;
}

let kind = plugin.plugin_kind().to_owned();
let allows_multiple_components = plugin.allows_multiple_components();
let Some(kind_handle) = HostString::new(host_ref, &kind) else {
return NemoRelayStatus::Internal;
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the relevant functions/macros in crates/plugin/src/lib.rs
ast-grep outline crates/plugin/src/lib.rs --view expanded || true

printf '\n--- search export_plugin / macro sites ---\n'
rg -n "export_plugin|catch_unwind|NemoRelayNativePluginV1::default|NullPointer|InvalidArg" crates/plugin/src/lib.rs

printf '\n--- focused slice around the reported lines ---\n'
sed -n '2610,2705p' crates/plugin/src/lib.rs

Repository: NVIDIA/NeMo-Relay

Length of output: 18934


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Provide line numbers and surrounding context for the relevant block.
nl -ba crates/plugin/src/lib.rs | sed -n '2618,2705p'

Repository: NVIDIA/NeMo-Relay

Length of output: 195


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the exported helper and the macro expansion target.
nl -ba crates/plugin/src/lib.rs | sed -n '2580,2665p'
printf '\n---\n'
nl -ba crates/plugin/src/lib.rs | sed -n '2665,2715p'

Repository: NVIDIA/NeMo-Relay

Length of output: 195


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Minimal verification: inspect the functions surrounding the reported lines.
nl -ba crates/plugin/src/lib.rs | sed -n '2620,2705p'

Repository: NVIDIA/NeMo-Relay

Length of output: 195


Move the constructor behind the argument checks, and clear the output on failure.

  • The generated entry wrapper evaluates $constructor() before export_plugin(), so invalid host/out pointers still trigger constructor side effects.
  • export_plugin() should initialize *out to NemoRelayNativePluginV1::default() after the null check, before ABI/version/allocation failure paths, so callers don’t observe stale descriptor contents.
🤖 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/src/lib.rs` around lines 2633 - 2648, Move the plugin
constructor work behind the `host`/`out` validation in `export_plugin()` so
invalid pointers return before any constructor side effects run. Also clear
`*out` to `NemoRelayNativePluginV1::default()` immediately after the null check
and before any ABI/version/allocation failures, so callers never see stale
plugin data. Use the existing `export_plugin`, `plugin.plugin_kind()`, and
`HostString::new` flow to keep the constructor-dependent setup after the early
checks.

Comment on lines +1578 to +1580
let (status, chunk) = poll_stream_chunk(&host, &stream);
assert_eq!(status, NemoRelayStatus::Ok);
assert_eq!(chunk.unwrap()["chunk"], json!(2));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert wrapping on every streamed chunk.

The callback maps all chunks, but the test only verifies "wrapped" on the first chunk. Check it on the second chunk too so later chunks cannot silently bypass the typed stream wrapper.

As per path instructions, tests in crates/**/tests/** should cover the behavior promised by the changed API surface.

Suggested assertion
     let (status, chunk) = poll_stream_chunk(&host, &stream);
     assert_eq!(status, NemoRelayStatus::Ok);
-    assert_eq!(chunk.unwrap()["chunk"], json!(2));
+    let chunk = chunk.unwrap();
+    assert_eq!(chunk["chunk"], json!(2));
+    assert_eq!(chunk["wrapped"], json!(true));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let (status, chunk) = poll_stream_chunk(&host, &stream);
assert_eq!(status, NemoRelayStatus::Ok);
assert_eq!(chunk.unwrap()["chunk"], json!(2));
let (status, chunk) = poll_stream_chunk(&host, &stream);
assert_eq!(status, NemoRelayStatus::Ok);
let chunk = chunk.unwrap();
assert_eq!(chunk["chunk"], json!(2));
assert_eq!(chunk["wrapped"], json!(true));
🤖 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 1578 - 1580, The typed
stream wrapper is only being verified on the first chunk, so this test can miss
later chunks bypassing the wrapper; update the streamed chunk assertions in the
typed callbacks test to also validate the second chunk includes the expected
wrapped shape using the existing poll_stream_chunk flow and the chunk result, so
the behavior promised by the callback mapping is covered consistently across all
emitted chunks.

Source: Path instructions

Comment on lines +1623 to +1635
let mut stream = NemoRelayNativeLlmStreamV1::default();
let status = unsafe {
(registration.cb)(
registration.user_data as *mut c_void,
name,
request,
failing_llm_stream_next,
next_state.cast(),
&mut stream,
)
};
assert_eq!(status, NemoRelayStatus::Internal);
assert!(stream.next.is_none());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Assert the failed stream output stays fully uninitialized.

Line 1635 only checks next; a regression could still leave user_data, cancel, or drop set after returning Internal, creating an ambiguous ABI ownership handoff.

As per path instructions, tests in crates/**/tests/** should cover the behavior promised by the changed API surface, including error paths.

Suggested test tightening
     assert_eq!(status, NemoRelayStatus::Internal);
+    assert_eq!(
+        stream.struct_size,
+        NemoRelayNativeLlmStreamV1::default().struct_size
+    );
+    assert!(stream.user_data.is_null());
     assert!(stream.next.is_none());
+    assert!(stream.cancel.is_none());
+    assert!(stream.drop.is_none());
     assert_eq!(called.load(Ordering::SeqCst), 1);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let mut stream = NemoRelayNativeLlmStreamV1::default();
let status = unsafe {
(registration.cb)(
registration.user_data as *mut c_void,
name,
request,
failing_llm_stream_next,
next_state.cast(),
&mut stream,
)
};
assert_eq!(status, NemoRelayStatus::Internal);
assert!(stream.next.is_none());
let mut stream = NemoRelayNativeLlmStreamV1::default();
let status = unsafe {
(registration.cb)(
registration.user_data as *mut c_void,
name,
request,
failing_llm_stream_next,
next_state.cast(),
&mut stream,
)
};
assert_eq!(status, NemoRelayStatus::Internal);
assert_eq!(
stream.struct_size,
NemoRelayNativeLlmStreamV1::default().struct_size
);
assert!(stream.user_data.is_null());
assert!(stream.next.is_none());
assert!(stream.cancel.is_none());
assert!(stream.drop.is_none());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/plugin/tests/typed_callbacks.rs` around lines 1623 - 1635, The
failing-stream test only verifies that NemoRelayNativeLlmStreamV1::next is
unset, but the ABI contract also requires the whole output struct to remain
uninitialized on Internal. Tighten the typed_callbacks.rs test around the
registration.cb invocation by asserting that NemoRelayNativeLlmStreamV1 fields
such as user_data, cancel, and drop are also still None after
failing_llm_stream_next returns failure, so the regression is covered for the
full output state.

Source: Path instructions


fn validate(&self, plugin_config: &Map<String, Json>) -> Vec<ConfigDiagnostic> {
let mut diagnostics = Vec::new();
let known_fields = ["tag", "block_tools", "block_llms", "emit_isolated_scope"];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Field knowledge is triplicated.

The config field names live in three places: the ExampleConfig struct (lines 13-17), parse (lines 35-55), and known_fields here. Adding a field means updating all three, and forgetting known_fields would emit a spurious "unknown config field" warning for a field the plugin actually consumes. Consider deriving known_fields from a single source.

🤖 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 `@examples/rust-native-plugin/src/lib.rs` at line 72, The config field list is
duplicated across ExampleConfig, parse, and known_fields, which can drift and
cause false unknown-field warnings. Update the logic around known_fields in
lib.rs so it is derived from a single source of truth used by ExampleConfig and
parse, rather than being maintained as a hardcoded list. Keep the field names in
one shared definition or generated from the config representation, and ensure
the warning check uses that shared set.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants