Skip to content

feat: layer code-driven plugin config over materialized file configs#211

Open
zhongxuanwang-nv wants to merge 14 commits into
NVIDIA:mainfrom
zhongxuanwang-nv:feat/relay-183-code-driven-plugin-config-layer
Open

feat: layer code-driven plugin config over materialized file configs#211
zhongxuanwang-nv wants to merge 14 commits into
NVIDIA:mainfrom
zhongxuanwang-nv:feat/relay-183-code-driven-plugin-config-layer

Conversation

@zhongxuanwang-nv
Copy link
Copy Markdown
Member

@zhongxuanwang-nv zhongxuanwang-nv commented Jun 4, 2026

Overview

Layer code-driven plugin config on top of the materialized file-based plugins.toml configs (RELAY-183). A direct integration that calls plugin.initialize(...) now resolves the same plugins.toml layering the gateway uses as its base instead of starting empty; the code-driven config is the authoritative top layer.

  • 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

  • initialize_plugins(config) resolves the discovered plugins.toml layering (system → project → user) as a base and layers config on top, so every binding inherits the file layering with no binding code changes.
  • initialize_plugins_exact(config) activates an already-materialized config without discovery; the gateway uses it so --config / --plugin-config source rules are unchanged.
  • File discovery + TOML parsing live in core: toml is a direct dependency and load_plugin_config_files (#[doc(hidden)]) is the shared read/parse/merge primitive the CLI delegates to.
  • Trade-off: toml + the filesystem discovery compile into every core build, including wasm (where discovery finds no files at runtime, so the base is empty).

Precedence — code-vs-file differs from file-vs-file. File-vs-file uses omit = inherit. Code-vs-file treats the code document as authoritative: you inherit any component kind or config key you omit, but the typed fields (version, policy, and a declared component's enabled) always take the code value (serde defaults included) — because bindings deserialize to the typed PluginConfig before core sees it, so "set" vs "defaulted" is already lost.

Constraints

Kept:

  • No struct/datatype changes — PluginConfig / PluginComponentSpec / ConfigPolicy untouched.
  • No public binding API changes — plugin.initialize(...) signatures unchanged across bindings.

Relaxed (with reason):

  • No public API changes — two pub fns added (initialize_plugins_exact, load_plugin_config_files), both #[doc(hidden)] for cross-crate gateway use; the gateway needs a no-discovery path distinct from the now-discovering initialize_plugins.

Tests

Core unit tests for load_plugin_config_files (merge precedence, per-file duplicate-kind rejection, absent files); existing CLI file-discovery tests exercise the same shared primitive.

Where should the reviewer start?

crates/core/src/plugin.rsinitialize_plugins (base-layer + overlay), initialize_plugins_exact, and the discovery / load_plugin_config_files. The precedence decision is the key thing to confirm.

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

  • Relates to RELAY-183

Summary by CodeRabbit

Release Notes

  • New Features

    • Plugin configuration now supports layering across multiple sources with clear precedence rules, allowing configuration files, inline settings, and code-driven overrides to be combined effectively.
    • Improved handling of multi-instance component configurations.
  • Documentation

    • Updated plugin configuration documentation to explain the layering mechanism and configuration discovery process.

Augment initialize_plugins so a code-driven plugin config layer, set via the new set_code_driven_plugin_config runtime API, is merged on top of the file/CLI-resolved config before validation and activation. The code-driven layer is the highest-precedence source and overrides discovered plugins.toml / [plugins].config / --plugin-config per-field; with no layer set, behavior is unchanged so file-only configs stay compatible.

nemo-relay doctor now surfaces the effective plugin config source (code-driven layer vs file/CLI) and validates the merged effective config. Docs document the layering model, precedence, and conflict behavior.

Additive and Rust-only: two new public functions in nemo_relay::plugin (set_code_driven_plugin_config, apply_code_driven_plugin_config). No existing API, struct/datatype, or language-binding changes.

Relates to relay-183.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 4, 2026

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 JSON layering primitive for plugin configs, integrates file-based TOML discovery into core, exposes an exact initialization entrypoint, updates CLI/server callers to use core merging, expands tests for merge/precedence behavior, and documents configuration layering and precedence.

Changes

Plugin Configuration Layering Helper

Layer / File(s) Summary
Core layer_config merge function & init exact
crates/core/src/plugin.rs
Adds layer_config and helpers for recursive JSON merging with positional components-array pairing by kind, and exposes initialize_plugins_exact as the activation path.
layer_config merge behavior tests & file-precedence tests
crates/core/tests/unit/plugin_tests.rs
Adds tests: test_layer_config_overlay_wins, test_layer_config_preserves_multi_instance_kinds, test_load_plugin_config_files_merges_files_by_precedence, and test_layer_config_applies_typed_overlay_defaults_over_file_base to validate merge semantics and precedence.
CLI TOML loader refactor
crates/cli/src/config.rs
Delegates plugins.toml discovery and merging to nemo_relay::plugin::load_plugin_config_files, removing local TOML merge helpers and returning merged JSON plus source paths.
Server plugin activation change
crates/cli/src/server.rs
Server startup now calls initialize_plugins_exact(...) with already-resolved/merged config and does not re-discover plugin files.
Dependencies and docs
crates/core/Cargo.toml, docs/build-plugins/plugin-configuration-files.mdx
Adds toml and tempfile deps; updates docs to describe mutually exclusive discovery sources and the configuration layering rules (file base + code-driven typed overlay with specified precedence).

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title follows Conventional Commits format with 'feat' type and concise imperative summary under 72 characters.
Description check ✅ Passed Description includes all required sections: Overview with issue reference, Details with key changes, constraints, tests, reviewer guidance, and Related Issues.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions github-actions Bot added size:L PR is large Feature a new feature lang:rust PR changes/introduces Rust code labels Jun 4, 2026
@zhongxuanwang-nv
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 4, 2026

✅ Action performed

Review finished.

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@crates/core/src/plugin.rs`:
- Around line 924-954: The code-driven layer can change concurrently because you
only lock the PLUGIN_CONFIG_CODE_DRIVEN_LAYER in
apply_code_driven_plugin_config(), so a setter (set_code_driven_plugin_config)
may mutate/clear the layer after you compute the merge but before you activate
plugins or write active_plugin_report(), leaving runtime state and report
out-of-sync; fix by serializing the merge + activation/report storage under the
same mutex: modify initialize_plugins (and any activation/report write paths
that call apply_code_driven_plugin_config) to lock
PLUGIN_CONFIG_CODE_DRIVEN_LAYER, call merge_plugin_config_layers while holding
the lock, perform plugin activation and write active_plugin_report() (or store
any activation marker) before releasing the lock, or alternatively change
apply_code_driven_plugin_config to return a (merged_config, layer_token) while
retaining the lock via a scoped guard that the caller uses to perform
activation/reporting, ensuring set_code_driven_plugin_config cannot mutate the
layer until activation/report storage completes.
- Around line 980-993: merge_plugin_config_layers currently finds the first base
component with the same kind and always merges into it, which drops additional
base instances of the same kind; change the merge to perform a one-to-one match:
clone base.components into components, keep a matched flag array (or
remove/consume matched entries) and for each overlay.components try to find the
first unmatched component in components with the same kind; if found mark it
matched and merge (existing.enabled = overlay.enabled; merge_json_object(&mut
existing.config, overlay.config.clone())), otherwise push overlay.clone() so
additional overlay instances are appended and not lost.
🪄 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: 0e4486e5-d6fd-40cc-8d2b-1a65b79fd46f

📥 Commits

Reviewing files that changed from the base of the PR and between f7c9415 and 4be77d6.

📒 Files selected for processing (7)
  • crates/cli/src/doctor.rs
  • crates/cli/tests/coverage/doctor_tests.rs
  • crates/core/Cargo.toml
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/tests/unit/plugin_tests.rs
  • docs/build-plugins/plugin-configuration-files.mdx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Check / Run
  • GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (27)
**/{Cargo.toml,**/*.rs}

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

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

Files:

  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/cli/src/doctor.rs
  • crates/cli/tests/coverage/doctor_tests.rs
{crates/core,crates/adaptive}/**/*

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

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

Files:

  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
**/*.{rs,toml}

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

Update Rust crate names and module prefixes during coordinated rename operations

Files:

  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/cli/src/doctor.rs
  • crates/cli/tests/coverage/doctor_tests.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/core/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>.

Files:

  • crates/core/Cargo.toml
crates/{core,adaptive}/**

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

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

Files:

  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.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:

  • crates/core/Cargo.toml
  • docs/build-plugins/plugin-configuration-files.mdx
**/*.{md,mdx,py,sh,yaml,yml,toml,json}

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

Keep package names, repo references, and build commands current

Files:

  • crates/core/Cargo.toml
  • docs/build-plugins/plugin-configuration-files.mdx
**/*.toml

📄 CodeRabbit inference engine (CONTRIBUTING.md)

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

Files:

  • crates/core/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/core/Cargo.toml
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/cli/src/doctor.rs
  • crates/cli/tests/coverage/doctor_tests.rs
**/*.rs

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

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

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

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

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

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

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

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

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

**/*.rs: Use cargo fmt for Rust code formatting
Run cargo clippy -- -D warnings to lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code with uv run pre-commit run --all-files to enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/cli/src/doctor.rs
  • crates/cli/tests/coverage/doctor_tests.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}

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

Maintain documented and tested validation and report behavior for adaptive surfaces

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/cli/tests/coverage/doctor_tests.rs
**/*.{h,hpp,c,cpp,rs}

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

Ensure FFI header and library naming follows consistent conventions across platform-specific builds

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/cli/src/doctor.rs
  • crates/cli/tests/coverage/doctor_tests.rs
crates/core/**/*.rs

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

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

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

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
**/*.{rs,py,go,js,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions: Rust and Python use snake_case, C FFI exports prefixed nemo_relay_, Go uses PascalCase for public APIs, Node.js uses camelCase.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/cli/src/doctor.rs
  • crates/cli/tests/coverage/doctor_tests.rs
crates/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
Use Json = serde_json::Value in Rust-facing runtime APIs for JSON payload handling.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/cli/src/doctor.rs
  • crates/cli/tests/coverage/doctor_tests.rs
crates/{core,adaptive}/**/*.rs

⚙️ CodeRabbit configuration file

crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}

⚙️ CodeRabbit configuration file

{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/cli/tests/coverage/doctor_tests.rs
{docs/**,README.md,CONTRIBUTING.md}

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

{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Use just docs for docs-site builds and just docs-linkcheck when links changed
Run docs site build with just docs

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md,CONTRIBUTING.md,**/*.md}

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

Run docs link validation with just docs-linkcheck when links change

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md}

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

Verify README and docs entry points still match current package names and paths for large or public-facing changes

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,examples/**,README.md}

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

Verify examples still run with documented commands for large or public-facing changes

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*.mdx

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*.{html,md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in HTML and Markdown files using HTML comment syntax

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
docs/**

📄 CodeRabbit inference engine (CONTRIBUTING.md)

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}

⚙️ CodeRabbit configuration file

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
🪛 LanguageTool
docs/build-plugins/plugin-configuration-files.mdx

[style] ~267-~267: Consider replacing this word to strengthen your wording.
Context: ... same process. It is a Rust runtime API and is not exposed to the Python, Node.js, ...

(AND_THAT)

🔇 Additional comments (9)
docs/build-plugins/plugin-configuration-files.mdx (1)

72-272: LGTM!

crates/cli/src/doctor.rs (3)

17-19: LGTM!


575-587: LGTM!


589-698: LGTM!

crates/cli/tests/coverage/doctor_tests.rs (2)

660-718: LGTM!


720-754: 💤 Low value

Global wiring is only covered indirectly. collect_observability_layered(...) is exercised directly in these tests, but the process-global code-driven layer (set_code_driven_plugin_config) is only referenced in the core plugin layer tests, not in crates/cli/tests/coverage/doctor_tests.rs; the doctor tests that call collect_observability(&gateway).await don’t appear to set the global layer, so regressions in collect_observability’s base parsing + apply_code_driven_plugin_config merge precedence could slip through.

crates/core/tests/unit/plugin_tests.rs (1)

302-302: LGTM!

Also applies to: 318-420

crates/core/Cargo.toml (1)

121-123: Please confirm the required Rust validation matrix ran for this new test target.

This adds a dedicated integration binary, so please verify the PR ran just test-rust, cargo fmt --all, and cargo clippy --workspace --all-targets -- -D warnings.

As per coding guidelines, **/*.rs: If any Rust code changed, always run just test-rust; also run cargo fmt --all; also run cargo clippy --workspace --all-targets -- -D warnings.

crates/core/tests/integration/plugin_layer_tests.rs (1)

1-105: LGTM!

Comment thread crates/core/src/plugin.rs Outdated
Comment thread crates/core/src/plugin.rs Outdated
@zhongxuanwang-nv zhongxuanwang-nv self-assigned this Jun 4, 2026
merge_plugin_config_layers now pairs components by kind in order of appearance instead of always merging into the first match, so repeated kinds (multi-instance plugins) are no longer collapsed or dropped. Also slim the layer integration test to the apply path (merge correctness is covered by the unit tests) and tighten the new doc comments.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
@zhongxuanwang-nv zhongxuanwang-nv marked this pull request as ready for review June 4, 2026 05:20
@zhongxuanwang-nv zhongxuanwang-nv requested a review from a team as a code owner June 4, 2026 05:20
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
crates/core/tests/integration/plugin_layer_tests.rs (1)

13-34: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Cover initialize_plugins in the dedicated layer test binary.

This test only exercises the pure accessor. The behavior that matters externally is initialize_plugins consuming the layer, activating the merged config, and making active_plugin_report() reflect that effective config. Without that path here, regressions in the activation/reporting contract can slip through.

As per coding guidelines, {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.

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

In `@crates/core/tests/integration/plugin_layer_tests.rs` around lines 13 - 34,
The test currently only calls the accessor apply_code_driven_plugin_config and
never goes through the activation path; update the test to call
initialize_plugins (the real activation function) after setting
set_code_driven_plugin_config(Some(...)) and then assert that
active_plugin_report() reflects the merged/effective PluginConfig (including the
relay183.example component), and finally call initialize_plugins or the
appropriate teardown/cleanup to restore isolation and confirm
active_plugin_report() becomes None after set_code_driven_plugin_config(None);
use the existing symbols apply_code_driven_plugin_config,
set_code_driven_plugin_config, initialize_plugins, and active_plugin_report to
implement this activation/verification flow in the test binary.
♻️ Duplicate comments (1)
crates/core/src/plugin.rs (1)

919-926: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Serialize the layer snapshot with activation/reporting.

Line 925 computes an effective config under the layer mutex, but initialize_plugins then validates, activates, and stores active_plugin_report() after that lock is gone. A concurrent set_code_driven_plugin_config(...) can change the process-global layer mid-initialization, leaving the active runtime state/report out of sync with the current layer.

As per coding guidelines, crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.

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

In `@crates/core/src/plugin.rs` around lines 919 - 926, The code computes an
effective config while holding the PLUGIN_CONFIG_CODE_DRIVEN_LAYER lock inside
apply_code_driven_plugin_config but then initialize_plugins validates/activates
and stores active_plugin_report after the lock is released, allowing a
concurrent set_code_driven_plugin_config to change the global layer
mid-initialization; fix by snapshotting the layer under the
PLUGIN_CONFIG_CODE_DRIVEN_LAYER mutex (e.g., clone or serialize the layer value
while inside the lock in apply_code_driven_plugin_config), return/propagate that
immutable snapshot to initialize_plugins/merge_plugin_config_layers so that
validation/activation/reporting (active_plugin_report) always operate on the
exact serialized layer snapshot rather than a mutable global reference, ensuring
consistency between activation and the stored report.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@crates/core/tests/integration/plugin_layer_tests.rs`:
- Around line 13-34: The test currently only calls the accessor
apply_code_driven_plugin_config and never goes through the activation path;
update the test to call initialize_plugins (the real activation function) after
setting set_code_driven_plugin_config(Some(...)) and then assert that
active_plugin_report() reflects the merged/effective PluginConfig (including the
relay183.example component), and finally call initialize_plugins or the
appropriate teardown/cleanup to restore isolation and confirm
active_plugin_report() becomes None after set_code_driven_plugin_config(None);
use the existing symbols apply_code_driven_plugin_config,
set_code_driven_plugin_config, initialize_plugins, and active_plugin_report to
implement this activation/verification flow in the test binary.

---

Duplicate comments:
In `@crates/core/src/plugin.rs`:
- Around line 919-926: The code computes an effective config while holding the
PLUGIN_CONFIG_CODE_DRIVEN_LAYER lock inside apply_code_driven_plugin_config but
then initialize_plugins validates/activates and stores active_plugin_report
after the lock is released, allowing a concurrent set_code_driven_plugin_config
to change the global layer mid-initialization; fix by snapshotting the layer
under the PLUGIN_CONFIG_CODE_DRIVEN_LAYER mutex (e.g., clone or serialize the
layer value while inside the lock in apply_code_driven_plugin_config),
return/propagate that immutable snapshot to
initialize_plugins/merge_plugin_config_layers so that
validation/activation/reporting (active_plugin_report) always operate on the
exact serialized layer snapshot rather than a mutable global reference, ensuring
consistency between activation and the stored report.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: f454ab03-ef87-4e13-8f84-a18a83081e6d

📥 Commits

Reviewing files that changed from the base of the PR and between 4be77d6 and ceac635.

📒 Files selected for processing (4)
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/tests/unit/plugin_tests.rs
  • docs/build-plugins/plugin-configuration-files.mdx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Python / Package (windows-arm64)
  • GitHub Check: Python / Package (windows-amd64)
  • GitHub Check: WebAssembly / Test (windows-arm64)
🧰 Additional context used
📓 Path-based instructions (24)
{docs/**,README.md,CONTRIBUTING.md}

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

{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Use just docs for docs-site builds and just docs-linkcheck when links changed
Run docs site build with just docs

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md,CONTRIBUTING.md,**/*.md}

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

Run docs link validation with just docs-linkcheck when links change

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md}

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

Verify README and docs entry points still match current package names and paths for large or public-facing changes

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,examples/**,README.md}

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

Verify examples still run with documented commands for large or public-facing changes

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}

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

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*.{md,mdx,py,sh,yaml,yml,toml,json}

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

Keep package names, repo references, and build commands current

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*.mdx

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*.{html,md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in HTML and Markdown files using HTML comment syntax

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
docs/**

📄 CodeRabbit inference engine (CONTRIBUTING.md)

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}

⚙️ CodeRabbit configuration file

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*.rs

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

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

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

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

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

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

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

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

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

**/*.rs: Use cargo fmt for Rust code formatting
Run cargo clippy -- -D warnings to lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code with uv run pre-commit run --all-files to enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/src/plugin.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}

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

Maintain documented and tested validation and report behavior for adaptive surfaces

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
**/{Cargo.toml,**/*.rs}

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

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

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/src/plugin.rs
**/*.{h,hpp,c,cpp,rs}

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

Ensure FFI header and library naming follows consistent conventions across platform-specific builds

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/src/plugin.rs
{crates/core,crates/adaptive}/**/*

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

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

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/src/plugin.rs
**/*.{rs,toml}

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

Update Rust crate names and module prefixes during coordinated rename operations

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/src/plugin.rs
crates/core/**/*.rs

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

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

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

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/src/plugin.rs
crates/{core,adaptive}/**

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

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

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/src/plugin.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}

📄 CodeRabbit inference engine (AGENTS.md)

Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/src/plugin.rs
**/*.{rs,py,go,js,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions: Rust and Python use snake_case, C FFI exports prefixed nemo_relay_, Go uses PascalCase for public APIs, Node.js uses camelCase.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/src/plugin.rs
crates/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
Use Json = serde_json::Value in Rust-facing runtime APIs for JSON payload handling.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/src/plugin.rs
crates/{core,adaptive}/**/*.rs

⚙️ CodeRabbit configuration file

crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
  • crates/core/src/plugin.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}

⚙️ CodeRabbit configuration file

{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/integration/plugin_layer_tests.rs
🔇 Additional comments (1)
docs/build-plugins/plugin-configuration-files.mdx (1)

229-231: LGTM!

Comment thread docs/build-plugins/plugin-configuration-files.mdx Outdated
Comment thread docs/build-plugins/plugin-configuration-files.mdx Outdated
Arrays inside component config are replaced by the higher-precedence value.
Tables inside component config merge recursively.

## Code-Driven Configuration Layer
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This should NOT be exposed as a public API.

The layering should be described but it's not something that should be used invoked. Plugin initialize should be the only way it's done.

Comment thread docs/build-plugins/plugin-configuration-files.mdx Outdated
Comment thread docs/build-plugins/plugin-configuration-files.mdx Outdated
Comment thread crates/cli/src/doctor.rs
Comment thread crates/core/src/plugin.rs Outdated
Comment thread crates/core/src/plugin.rs Outdated
Comment thread crates/core/src/plugin.rs
nemo-relay doctor runs in its own process and never sets a code-driven layer, so it can never observe one; the layer-aware reporting was unreachable in the shipped CLI (only the unit tests, which set the layer in-process, exercised it). Restore the original file-only collect_observability, remove the two layered doctor tests, and drop the doctor sentence from the docs.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
@github-actions github-actions Bot added size:M PR is medium and removed size:L PR is large labels Jun 4, 2026
@zhongxuanwang-nv zhongxuanwang-nv marked this pull request as draft June 4, 2026 16:45
Add a single public core primitive, merge_plugin_config(&Value, &Value) -> Value: objects merge recursively, arrays and scalars are replaced by the overlay, and the top-level components array pairs entries by kind in order of appearance (so multi-instance kinds are not collapsed). The CLI's plugins.toml file-layer merging now calls it instead of the duplicate merge_plugin_toml/merge_plugin_components (merge_toml is kept for config.toml).

This replaces the process-global code-driven layer (set/apply plus the auto-apply in initialize_plugins) with a caller-driven primitive; initialize_plugins is unchanged and the merge holds no global state. Tests and docs updated; the layer integration test is removed.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
@zhongxuanwang-nv zhongxuanwang-nv changed the title feat: add code-driven plugin config layer feat: add merge_plugin_config for layering plugin configuration Jun 4, 2026
Rename the public merge primitive merge_plugin_config -> layer_config (core, the CLI call site, tests, and docs), rename the docs section to "Configuration Layering", and trim the over-verbose doc comments on the merge helpers.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
…I merge

layer_config / merge_plugin_components / merge_json_value now use the original in-place (&mut left, right) form, so they are faithful translations of the CLI's merge_plugin_toml / merge_plugin_components / merge_toml (on serde_json::Value, with the positional multi-instance pairing). Behavior is unchanged; the CLI call site, tests, and doc example are updated to match.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@crates/cli/src/config.rs`:
- Around line 762-763: The current call to
validate_plugin_toml_component_kinds(&path, &parsed) prevents repeated component
kinds in a single plugins.toml file; remove or change that enforcement so
duplicate kinds are allowed per-file (since layer_config supports positional
same-kind pairing). Specifically, either delete the
validate_plugin_toml_component_kinds(&path, &parsed) invocation where files are
merged, or update validate_plugin_toml_component_kinds to only validate
component shape/existence (not uniqueness), ensuring functions that merge layers
(the code that converts each file to JSON and merges with the shared core
primitive) still rely on layer_config positional semantics to handle same-kind
instances correctly.
🪄 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: d23b22e4-d2ba-482b-b713-de5fdbfd87a0

📥 Commits

Reviewing files that changed from the base of the PR and between c7c6fc2 and 2535602.

📒 Files selected for processing (4)
  • crates/cli/src/config.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/unit/plugin_tests.rs
  • docs/build-plugins/plugin-configuration-files.mdx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (25)
**/*.rs

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

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

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

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

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

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

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

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

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

**/*.rs: Use cargo fmt for Rust code formatting
Run cargo clippy -- -D warnings to lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code with uv run pre-commit run --all-files to enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/cli/src/config.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}

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

Maintain documented and tested validation and report behavior for adaptive surfaces

Files:

  • crates/core/tests/unit/plugin_tests.rs
**/{Cargo.toml,**/*.rs}

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

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

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/cli/src/config.rs
**/*.{h,hpp,c,cpp,rs}

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

Ensure FFI header and library naming follows consistent conventions across platform-specific builds

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/cli/src/config.rs
{crates/core,crates/adaptive}/**/*

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

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

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
**/*.{rs,toml}

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

Update Rust crate names and module prefixes during coordinated rename operations

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/cli/src/config.rs
crates/core/**/*.rs

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

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

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

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
crates/{core,adaptive}/**

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

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

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
**/*.{rs,py,js,ts,tsx,jsx,go,sh,toml,yaml,yml,md}

📄 CodeRabbit inference engine (AGENTS.md)

Keep SPDX headers on source, docs, scripts, and configuration files. The project is Apache-2.0.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/cli/src/config.rs
**/*.{rs,py,go,js,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions: Rust and Python use snake_case, C FFI exports prefixed nemo_relay_, Go uses PascalCase for public APIs, Node.js uses camelCase.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/cli/src/config.rs
crates/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

crates/**/*.rs: Keep async behavior on the existing tokio-based model. Bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
Use Json = serde_json::Value in Rust-facing runtime APIs for JSON payload handling.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
  • crates/cli/src/config.rs
crates/{core,adaptive}/**/*.rs

⚙️ CodeRabbit configuration file

crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}

⚙️ CodeRabbit configuration file

{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.

Files:

  • crates/core/tests/unit/plugin_tests.rs
{docs/**,README.md,CONTRIBUTING.md}

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

{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Use just docs for docs-site builds and just docs-linkcheck when links changed
Run docs site build with just docs

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md,CONTRIBUTING.md,**/*.md}

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

Run docs link validation with just docs-linkcheck when links change

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md}

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

Verify README and docs entry points still match current package names and paths for large or public-facing changes

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,examples/**,README.md}

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

Verify examples still run with documented commands for large or public-facing changes

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md,**/Cargo.toml,**/package.json,**/*.md}

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

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*.{md,mdx,py,sh,yaml,yml,toml,json}

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

Keep package names, repo references, and build commands current

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*.mdx

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*.{html,md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in HTML and Markdown files using HTML comment syntax

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
docs/**

📄 CodeRabbit inference engine (CONTRIBUTING.md)

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}

⚙️ CodeRabbit configuration file

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*config*.{rs,ts,py,go,js,json,yaml,yml}

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

Ensure dynamic config shape still matches the documented canonical model

Files:

  • crates/cli/src/config.rs
🧠 Learnings (22)
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**} : Maintain documented and tested validation and report behavior for adaptive surfaces

Applied to files:

  • crates/core/tests/unit/plugin_tests.rs
📚 Learning: 2026-05-21T22:51:04.073Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/test-go-binding/SKILL.md:0-0
Timestamp: 2026-05-21T22:51:04.073Z
Learning: Applies to crates/ffi/**/*.rs : If the change touched `crates/ffi`, also use `test-ffi-surface` for validation

Applied to files:

  • crates/core/tests/unit/plugin_tests.rs
📚 Learning: 2026-05-21T22:47:58.898Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-middleware/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:58.898Z
Learning: Applies to crates/core/src/api/runtime/state.rs : Add chain execution helpers to `NemoRelayContextState` following the pattern of existing methods like `tool_sanitize_request_chain` or `tool_request_intercepts_chain`

Applied to files:

  • crates/core/tests/unit/plugin_tests.rs
📚 Learning: 2026-05-21T22:47:58.898Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-middleware/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:58.898Z
Learning: Applies to crates/core/src/api/runtime/state.rs : Add registry fields as `SortedRegistry<GuardrailEntry<T>>` or `SortedRegistry<Intercept<T>>` to `NemoRelayContextState` in `crates/core/src/api/runtime/state.rs`

Applied to files:

  • crates/core/tests/unit/plugin_tests.rs
📚 Learning: 2026-05-29T21:25:49.977Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-29T21:25:49.977Z
Learning: Applies to crates/core/**/*.rs : Use `Json = serde_json::Value` in Rust-facing runtime APIs where the existing code expects JSON payloads.

Applied to files:

  • crates/core/src/plugin.rs
  • crates/cli/src/config.rs
📚 Learning: 2026-05-29T21:25:49.977Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-29T21:25:49.977Z
Learning: Applies to crates/**/*.rs : Use `Json = serde_json::Value` in Rust-facing runtime APIs for JSON payload handling.

Applied to files:

  • crates/core/src/plugin.rs
  • crates/cli/src/config.rs
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to crates/core/src/api/**/*.rs : Implement behavior first in Rust core API modules: `crates/core/src/api/` and related core modules such as `crates/core/src/api/runtime/`, `crates/core/src/codec/`, or `crates/core/src/json.rs`

Applied to files:

  • crates/core/src/plugin.rs
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**} : Maintain consistent plugin lifecycle across all language bindings (Python, Go, Node/WebAssembly, and Rust)

Applied to files:

  • crates/core/src/plugin.rs
  • docs/build-plugins/plugin-configuration-files.mdx
📚 Learning: 2026-05-21T22:49:09.811Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/maintain-optimizer/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:09.811Z
Learning: Applies to {crates/adaptive/**,python/nemo_relay/plugin.py,go/nemo_relay/**,**/node/**,**/wasm/**} : Keep plugin context surfaces aligned across all language implementations

Applied to files:

  • crates/core/src/plugin.rs
📚 Learning: 2026-05-21T22:50:43.254Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/small-fix/SKILL.md:0-0
Timestamp: 2026-05-21T22:50:43.254Z
Learning: Update documentation if public behavior changed

Applied to files:

  • crates/core/src/plugin.rs
📚 Learning: 2026-05-21T22:49:35.949Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/prepare-pr/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:35.949Z
Learning: Docs and examples must be updated for any public behavior changes

Applied to files:

  • crates/core/src/plugin.rs
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Do not use this skill for internal-only core refactors with no public API change

Applied to files:

  • crates/core/src/plugin.rs
  • docs/build-plugins/plugin-configuration-files.mdx
📚 Learning: 2026-05-21T22:48:05.982Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/contribute-api/SKILL.md:0-0
Timestamp: 2026-05-21T22:48:05.982Z
Learning: Include PR notes explaining the user-facing change for new API surfaces

Applied to files:

  • crates/core/src/plugin.rs
📚 Learning: 2026-05-27T02:34:30.939Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2026-05-27T02:34:30.939Z
Learning: Applies to docs/reference/** : Update relevant reference documentation for any public API changes

Applied to files:

  • crates/core/src/plugin.rs
📚 Learning: 2026-05-26T21:02:51.956Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/contribute-docs/SKILL.md:0-0
Timestamp: 2026-05-26T21:02:51.956Z
Learning: Prefer the documented public API, not internal shortcuts

Applied to files:

  • crates/core/src/plugin.rs
📚 Learning: 2026-05-21T22:48:05.982Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/contribute-api/SKILL.md:0-0
Timestamp: 2026-05-21T22:48:05.982Z
Learning: Update docs and examples in the same branch as public API changes

Applied to files:

  • crates/core/src/plugin.rs
📚 Learning: 2026-05-21T22:52:14.330Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/validate-change/SKILL.md:0-0
Timestamp: 2026-05-21T22:52:14.330Z
Learning: If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch

Applied to files:

  • crates/core/src/plugin.rs
📚 Learning: 2026-05-26T21:03:12.012Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/review-doc-style/SKILL.md:0-0
Timestamp: 2026-05-26T21:03:12.012Z
Learning: Applies to **/README.md|docs/index.md|python/nemo_relay/README.md|crates/*/README.md : Public behavior changes must be reflected in corresponding entry-point documentation (Must-Fix)

Applied to files:

  • docs/build-plugins/plugin-configuration-files.mdx
📚 Learning: 2026-05-26T21:03:12.012Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/review-doc-style/SKILL.md:0-0
Timestamp: 2026-05-26T21:03:12.012Z
Learning: Applies to **/README.md|docs/index.md|python/nemo_relay/README.md|crates/*/README.md : Update entry-point documentation (README.md, docs/index.md, package/crate READMEs, and binding-level source READMEs) whenever public behavior changes

Applied to files:

  • docs/build-plugins/plugin-configuration-files.mdx
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to crates/ffi/src/api/**/*.rs : Add or update FFI wrappers in relevant `crates/ffi/src/api/*.rs` modules, re-export through `crates/ffi/src/api/mod.rs`, and ensure generated `crates/ffi/nemo_relay.h` stays correct

Applied to files:

  • crates/cli/src/config.rs
📚 Learning: 2026-05-21T22:47:33.109Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/add-binding-feature/SKILL.md:0-0
Timestamp: 2026-05-21T22:47:33.109Z
Learning: Applies to crates/ffi/src/api/**/*.rs : Use `nemo_relay_` prefix for C FFI function names (e.g., `nemo_relay_tool_call`)

Applied to files:

  • crates/cli/src/config.rs
📚 Learning: 2026-05-21T22:49:46.956Z
Learnt from: CR
Repo: NVIDIA/NeMo-Relay PR: 0
File: .agents/skills/rename-surfaces/SKILL.md:0-0
Timestamp: 2026-05-21T22:49:46.956Z
Learning: Applies to **/*.{rs,toml} : Update Rust crate names and module prefixes during coordinated rename operations

Applied to files:

  • crates/cli/src/config.rs
🔇 Additional comments (5)
docs/build-plugins/plugin-configuration-files.mdx (3)

6-7: LGTM!


201-222: LGTM!


223-231: ⚡ Quick win

Update “internal primitive” wording for layer_config to match its actual Rust visibility

  • layer_config is declared as pub fn in crates/core/src/plugin.rs and is invoked by crates/cli/src/config.rs.
  • Adjust the docs (lines 223-231) to describe it as an internal/unsupported gateway mechanism for direct callers, rather than implying it’s not something Rust users can access—unless you intentionally hide it from the public Rust API (module visibility/re-exports and/or #[doc(hidden)]).
crates/core/src/plugin.rs (1)

902-979: LGTM!

crates/core/tests/unit/plugin_tests.rs (1)

318-393: LGTM!

Also applies to: 396-419

Comment thread crates/cli/src/config.rs Outdated
@willkill07
Copy link
Copy Markdown
Member

This is the core required feature:

Right now, if a user has direct integration and calls plugin.initialize(...) for the appropriate language binding, they only get configured what they explicitly configured.

We already have existing configuration layering for the CLI through various plugin.toml files.

Need: instead of the base configuration being empty, it should be resolved from pre-existing NeMo Relay plugin configuration layering.

@willkill07 willkill07 added this to the 0.4 milestone Jun 4, 2026
initialize_plugins now resolves the discovered plugins.toml layering as a base and layers the caller's config on top, so direct integrations (any binding) inherit the same file layering as the gateway instead of starting from an empty base. initialize_plugins_exact activates an already-materialized config without discovery; the CLI uses it so --config / --plugin-config source rules are unchanged.

File discovery and TOML parsing sit behind an opt-in config-files core feature, keeping the default and wasm builds free of toml/filesystem; the CLI and native bindings enable it, and the CLI read/parse/merge is de-duplicated onto the shared core load_plugin_config_files primitive. The caller's config is layered as a typed document, so version/policy/enabled carry serde defaults while component config bodies merge field-by-field.

Refs: RELAY-183
Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
@github-actions github-actions Bot added size:L PR is large and removed size:M PR is medium labels Jun 5, 2026
The optional config-files feature gated plugins.toml discovery and the TOML parser out of core's default/wasm builds. Removing it makes toml a direct core dependency and discovery unconditional, dropping the feature flag, all #[cfg] gates, and the per-binding feature lines. Trade-off: toml and the filesystem discovery now compile into every core build, including wasm (where discovery finds no files, so the base is empty). Also trims the doc comments on the new plugin-init and discovery functions.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
@github-actions github-actions Bot added size:M PR is medium and removed size:L PR is large labels Jun 5, 2026
Adds core unit tests for load_plugin_config_files (merge by precedence, per-file duplicate-kind rejection, absent-files case) and documents the code-driven layering model and its precedence in the plugin configuration docs. Restores the original initialize_plugins doc on initialize_plugins_exact.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
@github-actions github-actions Bot added size:L PR is large and removed size:M PR is medium labels Jun 5, 2026
@zhongxuanwang-nv zhongxuanwang-nv changed the title feat: add merge_plugin_config for layering plugin configuration feat: layer code-driven plugin config over materialized file configs Jun 5, 2026
Internal gateway entry (no-discovery activation), not a documented public API — same treatment as load_plugin_config_files.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
Source Precedence And Conflicts duplicated the Discovery section (same source classes, mutual exclusivity, and precedence order); removed it. Tightened Configuration Layering to the code-driven model and precedence, dropping the internal layer_config note and the multi-instance aside.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
layer_config has no external callers — the CLI uses load_plugin_config_files and its tests are inline — so it drops pub and is fully internal to core's plugin module.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
Drops the duplicate-kind test (the CLI's plugins_toml_rejects_duplicate_component_kinds_per_file already covers that path through the shared loader) and the trivial absent-file test; adds a hermetic test pinning the code-vs-file typed-overlay precedence: a typed config's default version/policy/enabled override the file base, the config body merges, and an undeclared kind is inherited. Keeps the file-vs-file merge test.

Signed-off-by: Zhongxuan Wang <daniewang@nvidia.com>
@zhongxuanwang-nv
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 5, 2026

✅ Action performed

Review finished.

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@crates/core/src/plugin.rs`:
- Around line 1071-1099: load_plugin_config_files is performing blocking
filesystem and parse work (std::fs::read_to_string, toml::Table parsing,
serde_json::to_value) while being invoked from async initialize_plugins; offload
that work to the tokio blocking pool to avoid stalling the runtime by wrapping
the per-path blocking operations in tokio::task::spawn_blocking and awaiting the
JoinHandle inside load_plugin_config_files, or wrap the whole per-path block
(reading, parsing, validate_unique_component_kinds, layer_config) in
spawn_blocking so the function can remain synchronous for callers like
initialize_plugins; ensure errors are propagated back (map the JoinHandle result
and inner Result) and keep references to the same symbols
(load_plugin_config_files, validate_unique_component_kinds, layer_config,
initialize_plugins) so callers still compile.
🪄 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: db362eef-1db6-41b4-bd7a-cadf5f082488

📥 Commits

Reviewing files that changed from the base of the PR and between 2535602 and 70b4894.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • crates/cli/src/config.rs
  • crates/cli/src/server.rs
  • crates/core/Cargo.toml
  • crates/core/src/plugin.rs
  • crates/core/tests/unit/plugin_tests.rs
  • docs/build-plugins/plugin-configuration-files.mdx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Rust / Package (macos-arm64)
  • GitHub Check: Rust / Package (linux-arm64)
  • GitHub Check: Rust / Package (linux-amd64)
  • GitHub Check: Rust / Package (windows-arm64)
  • GitHub Check: Rust / Package (windows-amd64)
  • GitHub Check: Node.js / Test (windows-arm64)
  • GitHub Check: Python / Test (windows-arm64)
🧰 Additional context used
📓 Path-based instructions (29)
**/{Cargo.toml,**/*.rs}

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

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

Files:

  • crates/core/Cargo.toml
  • crates/cli/src/server.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/cli/src/config.rs
  • crates/core/src/plugin.rs
{crates/core,crates/adaptive}/**/*

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

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

Files:

  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
**/*.{rs,toml}

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

Update Rust crate names and module prefixes during coordinated rename operations

Files:

  • crates/core/Cargo.toml
  • crates/cli/src/server.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/cli/src/config.rs
  • crates/core/src/plugin.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/core/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>.

Files:

  • crates/core/Cargo.toml
crates/{core,adaptive}/**

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

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

Files:

  • crates/core/Cargo.toml
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.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:

  • crates/core/Cargo.toml
  • docs/build-plugins/plugin-configuration-files.mdx
**/*.{md,mdx,py,sh,yaml,yml,toml,json}

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

Keep package names, repo references, and build commands current

Files:

  • crates/core/Cargo.toml
  • docs/build-plugins/plugin-configuration-files.mdx
**/*.toml

📄 CodeRabbit inference engine (CONTRIBUTING.md)

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

Files:

  • crates/core/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/core/Cargo.toml
  • crates/cli/src/server.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/cli/src/config.rs
  • crates/core/src/plugin.rs
**

⚙️ CodeRabbit configuration file

**:

AGENTS.md

This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.

Project Overview

NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go, WebAssembly, and the raw C FFI are experimental and source-first.

The shared runtime model is:

  1. Scope stacks decide where work belongs and which scope-local behavior is visible.
  2. Middleware registries decide what guardrails and intercepts run around managed calls.
  3. Plugins install reusable runtime behavior from configuration.
  4. Events record runtime behavior in ATOF form.
  5. Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.

Repository Structure

The repository layout separates the Rust runtime, language bindings, documentation,
integration patches, and agent-facing skills.

crates/
  core/       # Rust core runtime crate, published as nemo-relay
  adaptive/   # Adaptive runtime primitives and plugin components
  python/     # PyO3 native extension for the Python package
  ffi/        # Raw C ABI layer used by downstream bindings such as Go
  node/       # NAPI Node.js binding and JavaScript/TypeScript entry points
  wasm/       # wasm-bindgen WebAssembly binding and JS wrappers
python/
  nemo_relay/  # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers
  tests/      # Python tests
go/
  nemo_relay/  # Experimental Go CGo binding and tests
fern/         # Fern documentation site
scripts/      # Stable wrappers and helper scripts; build/test/docs entry points live in justfile
third_party/  # P...

Files:

  • crates/core/Cargo.toml
  • crates/cli/src/server.rs
  • crates/core/tests/unit/plugin_tests.rs
  • docs/build-plugins/plugin-configuration-files.mdx
  • crates/cli/src/config.rs
  • crates/core/src/plugin.rs
**/*.rs

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

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

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

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

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

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

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

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

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

**/*.rs: Use cargo fmt for Rust code formatting
Run cargo clippy -- -D warnings to lint Rust code and treat all warnings as errors
Use Rust snake_case naming convention for Rust identifiers
Include SPDX license header in all Rust source files using double-slash comment syntax
Validate Rust code with uv run pre-commit run --all-files to enforce cargo fmt formatting check, cargo clippy lints, and cargo deny aud...

Files:

  • crates/cli/src/server.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/cli/src/config.rs
  • crates/core/src/plugin.rs
**/*.{h,hpp,c,cpp,rs}

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

Ensure FFI header and library naming follows consistent conventions across platform-specific builds

Files:

  • crates/cli/src/server.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/cli/src/config.rs
  • crates/core/src/plugin.rs
**/*.{rs,py,go,js,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions: Rust and Python use snake_case, C FFI exports prefixed nemo_relay_, Go uses PascalCase for public APIs, Node.js uses camelCase.

Files:

  • crates/cli/src/server.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/cli/src/config.rs
  • crates/core/src/plugin.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/cli/src/server.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/cli/src/config.rs
  • crates/core/src/plugin.rs
{crates/adaptive/**/*.rs,**/*test*.{rs,py,go,ts,js},**/*adaptive*test*.{rs,py,go,ts,js},docs/plugins/adaptive/**}

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

Maintain documented and tested validation and report behavior for adaptive surfaces

Files:

  • crates/core/tests/unit/plugin_tests.rs
crates/core/**/*.rs

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

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

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

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
crates/{core,adaptive}/**/*.rs

⚙️ CodeRabbit configuration file

crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.

Files:

  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/src/plugin.rs
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}

⚙️ CodeRabbit configuration file

{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.

Files:

  • crates/core/tests/unit/plugin_tests.rs
{docs/**,README.md,CONTRIBUTING.md}

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

{docs/**,README.md,CONTRIBUTING.md}: For docs-only changes, run targeted checks only if commands, package names, or examples changed. Use just docs for docs-site builds and just docs-linkcheck when links changed
Run docs site build with just docs

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md,CONTRIBUTING.md,**/*.md}

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

Run docs link validation with just docs-linkcheck when links change

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md}

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

Verify README and docs entry points still match current package names and paths for large or public-facing changes

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,examples/**,README.md}

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

Verify examples still run with documented commands for large or public-facing changes

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*.mdx

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

In MDX files, top-of-file comments must use JSX comment delimiters: {/* to open and */} to close. Do not use HTML comments for MDX SPDX headers.

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*.{html,md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Include SPDX license header in HTML and Markdown files using HTML comment syntax

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update embedded documentation snippets, patch docs, and binding-support notes if examples or supported bindings changed

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
docs/**

📄 CodeRabbit inference engine (CONTRIBUTING.md)

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
{docs/**,README.md,CONTRIBUTING.md,RELEASING.md,SECURITY.md}

⚙️ CodeRabbit configuration file

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

Files:

  • docs/build-plugins/plugin-configuration-files.mdx
**/*config*.{rs,ts,py,go,js,json,yaml,yml}

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

Ensure dynamic config shape still matches the documented canonical model

Files:

  • crates/cli/src/config.rs
🔇 Additional comments (16)
crates/cli/src/config.rs (2)

743-753: Delegation to core's shared loader looks good.

The error mapping correctly converts PluginError::InvalidConfig to CliError::Config while other variants fall back to .to_string().

Note: The past review comment about allowing repeated component kind values per file is still relevant—validate_unique_component_kinds in core still rejects duplicates within a single file. If multi-instance same-kind entries in one plugins.toml are intended, that validation needs adjustment in core.


4-13: LGTM!

Clean import changes reflecting the delegation to core's shared loader.

crates/core/src/plugin.rs (7)

902-923: LGTM!


925-958: LGTM!

The positional pairing via base_slots and consumed correctly preserves multi-instance component kinds, addressing the earlier concern about collapsing duplicates.


960-979: LGTM!


1008-1061: LGTM!

initialize_plugins_exact correctly retains the rollback/restore semantics, and initialize_plugins layers code-driven config on top of discovered file config as intended.


1063-1069: LGTM!


1101-1125: LGTM!


1127-1159: LGTM!

crates/core/tests/unit/plugin_tests.rs (2)

1422-1478: LGTM!

Good coverage of file precedence merging behavior - verifies inheritance of lower-file keys, override of shared keys, and appending of higher-only component kinds.


1480-1533: LGTM!

Solid test for the code-vs-file layering semantics, correctly verifying that typed defaults override file base while undeclared config fields merge.

crates/cli/src/server.rs (2)

10-10: LGTM!


160-165: LGTM!

Correct use of initialize_plugins_exact since the gateway has already resolved config via CLI paths. The comment clearly documents the intent.

crates/core/Cargo.toml (2)

89-89: LGTM!

tempfile is correctly placed in dev-dependencies for test filesystem isolation.


64-64: Keep toml pin consistent with Cargo.lock; confirm the MSRV/rationale for staying on 0.9.

  • crates/core/Cargo.toml pins toml = { version = "0.9" }, and Cargo.lock resolves it to toml 0.9.12+spec-1.1.0 (latest within the 0.9 major).
  • crates/cli/Cargo.toml also uses toml = "0.9", so the pin is workspace-consistent.
  • crates.io latest is 1.1.2+spec-1.1.0; if moving to 1.x is intentionally blocked for MSRV/behavior reasons, call that out—there’s no rust-version = ... field found to substantiate the MSRV constraint.
docs/build-plugins/plugin-configuration-files.mdx (1)

201-209: LGTM!

Documentation correctly describes the layering behavior for direct integrations without exposing internal APIs. The precedence semantics (typed defaults override file, omitted keys inherited) are clearly stated.

Comment thread crates/core/src/plugin.rs
@zhongxuanwang-nv
Copy link
Copy Markdown
Member Author

@willkill07 , sorry it took so long — I spent most of the time trying to decide where the toml discovery should belong and decide on the general architecture — but I;m wondering what do you think of the new changes? I also updated the PR body for this :)

@zhongxuanwang-nv zhongxuanwang-nv marked this pull request as ready for review June 5, 2026 05:00
@zhongxuanwang-nv zhongxuanwang-nv requested a review from a team as a code owner June 5, 2026 05:00
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:L PR is large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants