Skip to content

fix: report daemon bind and exporter status#345

Merged
rapids-bot[bot] merged 2 commits into
NVIDIA:mainfrom
willkill07:wkk_fix/relay-400-informative-bind-output
Jul 1, 2026
Merged

fix: report daemon bind and exporter status#345
rapids-bot[bot] merged 2 commits into
NVIDIA:mainfrom
willkill07:wkk_fix/relay-400-informative-bind-output

Conversation

@willkill07

@willkill07 willkill07 commented Jul 1, 2026

Copy link
Copy Markdown
Member

Overview

Add informative startup output to daemon mode so nemo-relay --bind ... reports the bound gateway address and configured exporter destinations. This addresses RELAY-400.

  • 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

Daemon startup now renders the same compact status frame used by transparent agent launches. It reports the listener's actual address, including the assigned port for --bind ...:0, and lists configured observability destinations. Existing exporter discovery is reused, and the output is written to stderr with terminal-aware color handling.

Where should the reviewer start?

Start with crates/cli/src/server.rs, especially the startup status rendering and its call immediately after listener binding. The focused regression test is in crates/cli/tests/coverage/server_tests.rs.

Validation completed:

  • Focused startup-status test passed.
  • CLI tests passed: 575 unit tests and 49 integration tests.
  • cargo clippy --workspace --all-targets -- -D warnings passed.
  • Targeted pre-commit checks, formatting, and cargo check passed.
  • just test-rust passed for core, adaptive, CLI, and other exercised targets but reported five unrelated existing FFI test failures.

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

  • Relates to: RELAY-400 (Linear)

Summary by CodeRabbit

  • New Features
    • Added a startup status banner that shows the bound gateway address and any configured exporter endpoints when the service launches.
    • Live status output is now rendered in a bordered frame, and startup/status formatting adapts to terminal color support while respecting NO_COLOR.
  • Bug Fixes
    • Startup output now clearly indicates when no exporter destinations are configured.
  • Tests
    • Added unit tests to verify startup banner formatting for both configured and unconfigured exporter scenarios.

@willkill07 willkill07 requested a review from a team as a code owner July 1, 2026 21:53
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds reusable status-frame rendering, prints a startup banner during server launch, and covers the rendered output for configured and unconfigured exporter cases.

Changes

Startup Status Banner

Layer / File(s) Summary
Status frame helpers
crates/cli/src/launcher.rs
print_live_status now renders from a reusable frame string, render_status_frame builds the bordered output, push_status_border appends border lines into a buffer, and exporter_destinations is crate-visible.
Startup banner wiring
crates/cli/src/server.rs
Imports SocketAddr, captures the bound local address in serve_with_dynamic, and renders startup status with TTY/NO_COLOR detection, gateway address formatting, exporter listing, and the shared frame helper.
Startup banner tests
crates/cli/tests/coverage/server_tests.rs
Tests assert the rendered startup status includes the gateway URL and exporter endpoint when configured, and reports exporters as not configured when absent.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant serve_with_dynamic
  participant print_startup_status
  participant render_startup_status
  participant exporter_destinations
  serve_with_dynamic->>print_startup_status: bound address, gateway config
  print_startup_status->>render_startup_status: TTY/NO_COLOR flag, address, config
  render_startup_status->>exporter_destinations: request exporter list
  exporter_destinations-->>render_startup_status: exporter endpoints
  render_startup_status-->>print_startup_status: formatted banner string
  print_startup_status-->>serve_with_dynamic: prints banner to stderr
Loading

Related PRs: None identified from provided context.
Suggested labels: cli, enhancement
Suggested reviewers: None identified from provided context.
Poem:
A banner blooms where sockets bind,
Exporters listed, borders lined,
pub(crate) now lets the data flow,
colors dim when NO_COLOR's aglow,
a rabbit's box, both neat and kind.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits and accurately summarizes the daemon status reporting change.
Description check ✅ Passed The description includes all required template sections and provides relevant implementation, review, and issue context.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions github-actions Bot added size:S PR is small Bug issue describes bug; PR fixes bug lang:rust PR changes/introduces Rust code labels Jul 1, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@crates/cli/src/server.rs`:
- Around line 73-139: The startup banner in
render_startup_status/push_status_border duplicates the bordered-box formatting
already implemented by print_live_status/eprint_border_line, so refactor to use
a shared box-rendering helper instead of maintaining two versions. Extract the
common logic for border characters, color escape handling, padding, and line
wrapping into a reusable function or writer-based helper that both
render_startup_status and print_live_status can call. Keep the unique message
content in each caller, but centralize the rendering behavior to prevent drift.

In `@crates/cli/tests/coverage/server_tests.rs`:
- Around line 173-198: Add a test for the fallback banner in
render_startup_status so the new “Exporters not configured” path is covered, not
just the OpenTelemetry-enabled branch. Create a case using test_config() (or a
GatewayConfig with plugin_config absent / observability disabled) and assert the
output contains the not-configured exporters message. Keep the existing
startup_status_reports_bound_gateway_and_exporters test focused on the
configured exporter path, and add a separate coverage test for the default
branch.
🪄 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: 419e8f77-bc57-4cd9-84b8-98a41e64e2b7

📥 Commits

Reviewing files that changed from the base of the PR and between cc3e5f1 and 7be0490.

📒 Files selected for processing (3)
  • crates/cli/src/launcher.rs
  • crates/cli/src/server.rs
  • crates/cli/tests/coverage/server_tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
**/*.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/tests/coverage/server_tests.rs
  • crates/cli/src/launcher.rs
  • crates/cli/src/server.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/cli/tests/coverage/server_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/cli/tests/coverage/server_tests.rs
  • crates/cli/src/launcher.rs
  • crates/cli/src/server.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/tests/coverage/server_tests.rs
  • crates/cli/src/launcher.rs
  • crates/cli/src/server.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/cli/tests/coverage/server_tests.rs
  • crates/cli/src/launcher.rs
  • crates/cli/src/server.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/cli/tests/coverage/server_tests.rs
  • crates/cli/src/launcher.rs
  • crates/cli/src/server.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/tests/coverage/server_tests.rs
  • crates/cli/src/launcher.rs
  • crates/cli/src/server.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/tests/coverage/server_tests.rs
  • crates/cli/src/launcher.rs
  • crates/cli/src/server.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 and the raw C FFI are experimental and source-first.

The shared runtime model is:

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

Repository Structure

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

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

Prerequisites

Insta...

Files:

  • crates/cli/tests/coverage/server_tests.rs
  • crates/cli/src/launcher.rs
  • crates/cli/src/server.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/cli/tests/coverage/server_tests.rs
🔇 Additional comments (2)
crates/cli/src/launcher.rs (1)

616-616: LGTM!

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

4-4: LGTM!

Also applies to: 69-71

Comment thread crates/cli/src/server.rs
Comment thread crates/cli/tests/coverage/server_tests.rs
@willkill07 willkill07 added this to the 0.5 milestone Jul 1, 2026
@willkill07 willkill07 self-assigned this Jul 1, 2026
Signed-off-by: Will Killian <wkillian@nvidia.com>
@willkill07 willkill07 force-pushed the wkk_fix/relay-400-informative-bind-output branch from 4ab294b to bc5bcbc Compare July 1, 2026 22:43

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
crates/cli/src/server.rs (1)

79-99: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exporter-line formatting still duplicated across files.

The border/frame rendering duplication flagged previously was fixed via render_status_frame/push_status_border, but the exporter-line-prefix loop ("Exporters " / " " indexing) is copy-pasted verbatim between this function and print_live_status in crates/cli/src/launcher.rs (lines 539-550). Consider extracting a shared format_exporter_lines(destinations: &[String]) -> Vec<String> helper alongside exporter_destinations to keep the two banners from drifting.

♻️ Proposed helper extraction
+pub(crate) fn format_exporter_lines(destinations: &[String]) -> Vec<String> {
+    if destinations.is_empty() {
+        return vec!["  Exporters      not configured".into()];
+    }
+    destinations
+        .iter()
+        .enumerate()
+        .map(|(index, destination)| {
+            format!(
+                "  {}{}",
+                if index == 0 { "Exporters      " } else { "               " },
+                destination
+            )
+        })
+        .collect()
+}
🤖 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/cli/src/server.rs` around lines 79 - 99, The exporter line prefix
logic is duplicated between render_startup_status and print_live_status, so
extract the shared formatting into a helper such as
format_exporter_lines(destinations: &[String]) that returns the banner lines for
both startup and live status output. Update render_startup_status to use that
helper instead of building the indexed "Exporters" prefix inline, and do the
same in print_live_status so both paths stay consistent and do not drift.
🤖 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/cli/src/server.rs`:
- Around line 79-99: The exporter line prefix logic is duplicated between
render_startup_status and print_live_status, so extract the shared formatting
into a helper such as format_exporter_lines(destinations: &[String]) that
returns the banner lines for both startup and live status output. Update
render_startup_status to use that helper instead of building the indexed
"Exporters" prefix inline, and do the same in print_live_status so both paths
stay consistent and do not drift.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 4dc1fbe0-b777-4d5e-a15b-bc8b361ce712

📥 Commits

Reviewing files that changed from the base of the PR and between 7be0490 and 4ab294b.

📒 Files selected for processing (3)
  • crates/cli/src/launcher.rs
  • crates/cli/src/server.rs
  • crates/cli/tests/coverage/server_tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
**/*.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/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/cli/tests/coverage/server_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/cli/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/cli/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/cli/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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 and the raw C FFI are experimental and source-first.

The shared runtime model is:

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

Repository Structure

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

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

Prerequisites

Insta...

Files:

  • crates/cli/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/cli/tests/coverage/server_tests.rs
🔇 Additional comments (3)
crates/cli/src/launcher.rs (1)

525-562: LGTM!

Also applies to: 600-623, 756-769

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

4-4: LGTM!

Also applies to: 69-71, 100-102

crates/cli/tests/coverage/server_tests.rs (1)

173-206: LGTM!

Signed-off-by: Will Killian <wkillian@nvidia.com>
@willkill07 willkill07 force-pushed the wkk_fix/relay-400-informative-bind-output branch from bc5bcbc to e639d6f Compare July 1, 2026 22:44
@github-actions github-actions Bot added size:M PR is medium and removed size:S PR is small labels Jul 1, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
crates/cli/src/launcher.rs (1)

535-550: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exporter-line formatting duplicated with server.rs::render_startup_status.

This loop (index-based "Exporters "/padding prefix, empty-case fallback string) is copied verbatim in server.rs at lines 93-107. This is the same class of divergence risk previously flagged for the border-drawing code (already fixed by extracting render_status_frame/push_status_border). Consider extracting a shared push_exporter_lines(lines: &mut Vec<String>, destinations: &[String]) helper alongside render_status_frame so both banners stay in sync.

♻️ Proposed shared helper
+pub(crate) fn push_exporter_lines(lines: &mut Vec<String>, destinations: &[String]) {
+    if destinations.is_empty() {
+        lines.push("  Exporters      not configured".into());
+    } else {
+        for (index, destination) in destinations.iter().enumerate() {
+            lines.push(format!(
+                "  {}{}",
+                if index == 0 { "Exporters      " } else { "               " },
+                destination
+            ));
+        }
+    }
+}

Then both print_live_status and server::render_startup_status call push_exporter_lines(&mut lines, &destinations).

🤖 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/cli/src/launcher.rs` around lines 535 - 550, The exporter banner
formatting in launcher::print_live_status is duplicated and should be shared
with server::render_startup_status to avoid drift. Extract the repeated
empty-case and indexed prefix logic into a helper like
push_exporter_lines(lines: &mut Vec<String>, destinations: &[String]) near the
existing status-frame helper, then call it from both print_live_status and
server::render_startup_status using the same exporter_destinations output.
♻️ Duplicate comments (1)
crates/cli/src/server.rs (1)

81-110: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate exporter-line loop (see companion comment in launcher.rs).

render_startup_status reimplements the same "Exporters" line-building logic as launcher::print_live_status. Extracting a shared helper (see comment on crates/cli/src/launcher.rs lines 535-550) would keep the two banners from drifting.

🤖 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/cli/src/server.rs` around lines 81 - 110, `render_startup_status` is
duplicating the exporter line-building logic that also exists in
`launcher::print_live_status`, so please refactor the shared “Exporters”
formatting into a common helper and have both call sites use it. Keep the helper
near the status rendering code so `print_startup_status` and
`render_startup_status` can reuse the same exporter destination text
construction without drifting apart.
🤖 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/cli/src/launcher.rs`:
- Around line 535-550: The exporter banner formatting in
launcher::print_live_status is duplicated and should be shared with
server::render_startup_status to avoid drift. Extract the repeated empty-case
and indexed prefix logic into a helper like push_exporter_lines(lines: &mut
Vec<String>, destinations: &[String]) near the existing status-frame helper,
then call it from both print_live_status and server::render_startup_status using
the same exporter_destinations output.

---

Duplicate comments:
In `@crates/cli/src/server.rs`:
- Around line 81-110: `render_startup_status` is duplicating the exporter
line-building logic that also exists in `launcher::print_live_status`, so please
refactor the shared “Exporters” formatting into a common helper and have both
call sites use it. Keep the helper near the status rendering code so
`print_startup_status` and `render_startup_status` can reuse the same exporter
destination text construction without drifting apart.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 8aa84bca-7727-4b57-9139-da2f7fef1ae8

📥 Commits

Reviewing files that changed from the base of the PR and between 4ab294b and e639d6f.

📒 Files selected for processing (3)
  • crates/cli/src/launcher.rs
  • crates/cli/src/server.rs
  • crates/cli/tests/coverage/server_tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
**/*.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/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/cli/tests/coverage/server_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/cli/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/cli/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/cli/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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 and the raw C FFI are experimental and source-first.

The shared runtime model is:

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

Repository Structure

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

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

Prerequisites

Insta...

Files:

  • crates/cli/tests/coverage/server_tests.rs
  • crates/cli/src/server.rs
  • crates/cli/src/launcher.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/cli/tests/coverage/server_tests.rs
🔇 Additional comments (4)
crates/cli/src/launcher.rs (2)

525-562: Clean extraction of the frame renderer.

render_status_frame/push_status_border correctly preserve prior padding, color, and box-drawing behavior while making the renderer reusable from server.rs. exporter_destinations visibility bump to pub(crate) is consistent with its new cross-module caller.

Also applies to: 600-625


756-769: LGTM!

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

4-6: LGTM!

Also applies to: 71-79

crates/cli/tests/coverage/server_tests.rs (1)

173-205: Both banner branches now covered.

startup_status_reports_bound_gateway_and_exporters and startup_status_reports_not_configured_when_no_exporters cover the configured/unconfigured exporter paths and the resolved bind address, addressing the previously flagged gap.

@zhongxuanwang-nv zhongxuanwang-nv left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks Will! All super nitty things!

Comment thread crates/cli/src/server.rs
Comment thread crates/cli/tests/coverage/server_tests.rs
@willkill07

Copy link
Copy Markdown
Member Author

/merge

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

Labels

Bug issue describes bug; PR fixes bug lang:rust PR changes/introduces Rust code size:M PR is medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants