Skip to content

feat(relay): NeMo Relay PreToolUse Rust client - #2493

Merged
tgasser-nv merged 7 commits into
developfrom
feat/relay-rust-pretooluse-client
Oct 27, 2026
Merged

tgasser-nv merged 7 commits into
developfrom
feat/relay-rust-pretooluse-client

Conversation

@tgasser-nv

@tgasser-nv tgasser-nv commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Description

This PR makes the NeMo Relay plugin from #2489 check tool calls. Before each tool call that Relay manages, the plugin posts the tool's name and arguments to the Guardrails hooks server's /v1/hooks/nemo-relay endpoint (nemoguardrails hooks-server, #2473). Relay blocks the call when the server denies it, and also when the check fails.
The plugin checks every call and keeps no earlier decisions: through Relay 0.10.4, a call that reaches a permission prompt is checked twice, on PreToolUse and on PermissionRequest; Relay 0.11 checks it once.

It's the second PR in a stack of five:

Related Issue(s)

Verification

Run locally on macOS arm64 with Rust 1.96.1:

  • cargo fmt --check and cargo clippy --all-targets -- -D warnings.
  • cargo test -p nemo-guardrails-relay-plugin: 12 unit tests (config and diagnostics), 15 client tests, 8 host lifecycle tests and 5 host tool call tests, with a Relay 0.10.4 host.
    The new tests ran against stubs first, and failed where the stub lacked the behavior: 14 of 15 client tests and all the host tool call tests.
    The tests that passed check what a stub can't get wrong, such as that no error repeats a header value.
    every_call_is_checked, which replaced the cache's test when the cache was removed, fails against the code with the cache: one request where it expects two.
  • Rebased onto feat(relay): NeMo Relay Rust plugin scaffold #2489's head f576c22bd; the checks above ran on the rebased branch.
  • Review changes: CheckFailure is now an enum (Unanswered, or Answered with a status and an optional error.code), and Verdict deserializes the server's answer directly, replacing Decision.
    For CheckFailure, the client tests moved to the enum's API first and failed to compile against the old struct; the Verdict change left the tests untouched.
    After both, all tests pass, and breaking each accessor, constructor and serde rule by hand fails at least one test.
  • cargo test --locked --release -p nemo-guardrails-relay-plugin, as the NeMo-Relay-Plugins release pipeline runs it.
  • make test TEST=crates/nemo-guardrails-relay-plugin/scripts/test_package_bundle.py: 8 tests of the packaging script.
  • cargo build --release --locked, then scripts/package_bundle.py with --archive, and nemo-relay plugins validate (CLI 0.10.4, from nemo-relay-cli-bin) on the bundle: valid.
  • License pre-check: all 353 packages in Cargo.lock, dev-dependencies included, have a license on NeMo-Relay-Plugins' accepted list.
  • pre-commit run --files on every file in this PR: passes, including the Rust license-header hook.

AI Assistance

  • No AI tools were used.
  • AI tools were used; a human reviewed and can explain every change (tool: Claude Code).

Checklist

  • I've read the CONTRIBUTING guidelines.
  • This PR links to a triaged issue assigned to me.
  • My PR title follows the project commit convention.
  • I've updated the documentation if applicable.
  • I've added tests if applicable.
  • I've noted any verification beyond CI and any checks I couldn't run.
  • I did not update generated changelog files manually.
  • I addressed all CodeRabbit, Greptile, and other review comments, or replied with why no change is needed.
  • @mentions of the person or team responsible for reviewing proposed changes.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Tool calls can now be checked against NeMo Guardrails before they run. Allowed calls proceed; denied calls are blocked with an optional reason.
    • Successful decisions are reused for identical calls for up to 10 seconds, with a limit of 1,024 cached decisions.
    • If a check fails, the tool call is blocked and a warning is recorded. Failed checks are not retried.
  • Documentation
    • Added guidance on guardrail outcomes, errors, Relay compatibility, and plugin behavior.

@github-actions github-actions Bot added status: needs triage New issues that have not yet been reviewed or categorized. size: XL labels Oct 23, 2026
@tgasser-nv
tgasser-nv changed the base branch from develop to feat/relay-rust-client October 23, 2026 19:32
@tgasser-nv tgasser-nv added status: triaged Triaged by a maintainer; eligible for automated review (CodeRabbit/Greptile). and removed status: needs triage New issues that have not yet been reviewed or categorized. labels Oct 23, 2026
@tgasser-nv tgasser-nv self-assigned this Oct 23, 2026
@tgasser-nv
tgasser-nv added this pull request to stack #2494 October 23, 2026 20:53
@tgasser-nv
tgasser-nv force-pushed the feat/relay-rust-pretooluse-client branch from 6df7314 to 7d2f1fa Compare October 23, 2026 20:56
@codecov

codecov Bot commented Oct 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@tgasser-nv
tgasser-nv marked this pull request as ready for review October 23, 2026 21:08
@greptile-apps

greptile-apps Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable new issues were found.

Summary

Adds tool-call checks against the NeMo Guardrails hooks server.

  • Relay checks each managed tool call with Guardrails before it runs.

The previous dependent-caller mismatch is resolved in #2504. This stack assessment uses that PR’s supplied revision; it does not attribute that fix to this PR.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Relay tool call] --> B[Plugin posts tool name and arguments]
    B --> C[Hooks server]
    C -->|Allow| D[Run tool]
    C -->|Deny| E[Reject tool call]
    C -->|Error or invalid answer| F[Return error and log warning]
    B -->|Timeout or connection failure| F
Loading

Reviews (8) · Last reviewed commit: "Update comments to refer to NeMo Guardra..." · Reviewed by Greptile

@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

ℹ️ Recent review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between d584c3e and 7d2f1fa.

⛔ Files ignored due to path filters: 1
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing: 9
  • crates/nemo-guardrails-relay-plugin/Cargo.toml
  • crates/nemo-guardrails-relay-plugin/README.md
  • crates/nemo-guardrails-relay-plugin/src/cache.rs
  • crates/nemo-guardrails-relay-plugin/src/client.rs
  • crates/nemo-guardrails-relay-plugin/src/lib.rs
  • crates/nemo-guardrails-relay-plugin/tests/client.rs
  • crates/nemo-guardrails-relay-plugin/tests/common/mod.rs
  • crates/nemo-guardrails-relay-plugin/tests/lifecycle.rs
  • crates/nemo-guardrails-relay-plugin/tests/tool_call_check.rs

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 10 remain after this review.

Walkthrough

The plugin registers a Relay tool-call guardrail that checks calls through the NeMo Guardrails hooks endpoint. It caches successful verdicts, maps allow and deny decisions to guardrail outcomes, and reports failed checks as errors.

Changes: Relay Tool-Call Guardrail

Layer / File(s) Summary
Hooks client and response handling
crates/nemo-guardrails-relay-plugin/src/client.rs, crates/nemo-guardrails-relay-plugin/tests/client.rs
The client sends tool name and input to the hooks endpoint, parses allow and deny decisions, and formats HTTP or transport failures. Tests cover request details, response parsing, redirects, timeouts, and connection failures.
Verdict key and cache behavior
crates/nemo-guardrails-relay-plugin/src/cache.rs, crates/nemo-guardrails-relay-plugin/Cargo.toml
The cache keys verdicts by the SHA-256 hash of the tool name and JSON arguments. It applies a TTL and capacity limit. Tests cover key identity, expiry, replacement, and eviction.
Guardrail registration and Relay integration
crates/nemo-guardrails-relay-plugin/src/lib.rs, crates/nemo-guardrails-relay-plugin/tests/tool_call_check.rs, crates/nemo-guardrails-relay-plugin/tests/common/mod.rs, crates/nemo-guardrails-relay-plugin/tests/lifecycle.rs, crates/nemo-guardrails-relay-plugin/README.md
The plugin registers the guardrail and maps cached or fetched verdicts to Relay outcomes. Integration tests cover allows, denials, failures, caching, and warning fields. Shared test helpers package and load the plugin into a Relay host; the README documents the behavior and test coverage.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Relay
  participant ToolCallCheck
  participant VerdictCache
  participant HooksClient
  participant HooksEndpoint
  Relay->>ToolCallCheck: invoke conditional-execution guardrail
  ToolCallCheck->>VerdictCache: look up tool name and arguments
  ToolCallCheck->>HooksClient: check call when cache has no verdict
  HooksClient->>HooksEndpoint: POST hook event, tool name, and input
  HooksEndpoint-->>HooksClient: return allow, deny, or failure response
  HooksClient-->>ToolCallCheck: return verdict or check failure
  ToolCallCheck->>VerdictCache: store successful verdict
  ToolCallCheck-->>Relay: return allow, rejection, or error
Loading

Possibly related PRs

Merge Risk: Minimal · up to 7d2f1

The tool-call check matches the hooks server’s protocol, and no actionable merge-blocking issue remains after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Test Results For Major Changes Warning The PR is a major runtime change: the diff adds a hooks-server HTTP check before managed tool calls and a verdict cache. The description documents extensive test commands and results, including client… Add before-and-after performance measurements for managed tool calls, including cache-hit and cache-miss cases. State the Relay and hooks-server versions, plugin configuration, workload, hardware, sample method, and measured latency/request…
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title "feat(relay): NeMo Relay PreToolUse Rust client" matches the main change. The PR adds a Rust HooksClient that calls the hooks server's /v1/hooks/nemo-relay endpoint before tool calls, and it…
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.
Full details: Title check

Explanation

The title "feat(relay): NeMo Relay PreToolUse Rust client" matches the main change. The PR adds a Rust HooksClient that calls the hooks server's /v1/hooks/nemo-relay endpoint before tool calls, and it registers a tool-call guardrail in the plugin. The title is concise, specific, and follows the conventional-commit style. It does not mention the verdict cache, but the cache is a supporting detail and not the main point.

Full details: Test Results For Major Changes

Explanation

The PR is a major runtime change: the diff adds a hooks-server HTTP check before managed tool calls and a verdict cache. The description documents extensive test commands and results, including client and host tool-call tests, but it provides no before-and-after performance numbers or the configuration and context for those measurements. The new network path and cache can affect tool-call latency and request volume, so the performance reporting requirement is not met.

Resolution

Add before-and-after performance measurements for managed tool calls, including cache-hit and cache-miss cases. State the Relay and hooks-server versions, plugin configuration, workload, hardware, sample method, and measured latency/request-volume results in the PR description.

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@tgasser-nv
tgasser-nv removed this pull request from stack #2494 October 26, 2026 21:36
@tgasser-nv
tgasser-nv added this pull request to stack #2506 October 26, 2026 21:37
@tgasser-nv
tgasser-nv force-pushed the feat/relay-rust-pretooluse-client branch from 7d2f1fa to d6d3d76 Compare October 27, 2026 18:48
Base automatically changed from feat/relay-rust-client to develop October 27, 2026 21:59
@tgasser-nv
tgasser-nv force-pushed the feat/relay-rust-pretooluse-client branch from 508aa2c to e994b93 Compare October 27, 2026 21:59
@tgasser-nv
tgasser-nv merged commit 7d2ef09 into develop Oct 27, 2026
20 checks passed
@tgasser-nv
tgasser-nv deleted the feat/relay-rust-pretooluse-client branch October 27, 2026 22:08
@tgasser-nv tgasser-nv mentioned this pull request Oct 29, 2026
11 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: XL status: triaged Triaged by a maintainer; eligible for automated review (CodeRabbit/Greptile).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants