Skip to content

fix(plugin): route registration banner to stderr - #5674

Closed
WilliamK112 wants to merge 2 commits into
NVIDIA:mainfrom
WilliamK112:codex/fix-plugin-banner-stderr
Closed

fix(plugin): route registration banner to stderr#5674
WilliamK112 wants to merge 2 commits into
NVIDIA:mainfrom
WilliamK112:codex/fix-plugin-banner-stderr

Conversation

@WilliamK112

@WilliamK112 WilliamK112 commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Routes the NemoClaw plugin registration banner directly to stderr instead of api.logger.info, so non-JSON nemoclaw <sandbox> agent passthrough stdout remains reserved for the agent reply.

Related Issue

Fixes #5654

Changes

  • Writes the registration banner with process.stderr.write.
  • Updates plugin registration tests to capture stderr.
  • Adds a regression assertion that the banner no longer uses api.logger.info.

Type of Change

  • Code change for a new feature, bug fix, or refactor.
  • Code change with doc updates.
  • Doc only. Prose changes without code sample modifications.
  • Doc only. Includes code sample changes.

Testing

  • npx prek run --all-files passes (or equivalently make check).
  • npm test passes.
  • make docs builds without warnings. (for doc-only changes)

Targeted checks run:

  • cd nemoclaw && npm test -- src/register.test.ts
  • cd nemoclaw && npm run lint -- src/index.ts src/register.test.ts
  • cd nemoclaw && npm run build

Checklist

General

  • I have read and followed the contributing guide.
  • I have read and followed the style guide. (for doc-only changes)

Code Changes

  • Tests added or updated for new or changed behavior.
  • No secrets, API keys, or credentials committed.
  • Doc pages updated for any user-facing behavior changes, or no doc update needed because this restores the expected stdout/stderr contract.

Signed-off-by: WilliamK112 164879897+WilliamK112@users.noreply.github.com

Summary by CodeRabbit

  • Refactor

    • Updated the plugin startup banner to write directly to standard error, improving reliability of banner rendering across environments.
  • Tests

    • Revised registration-banner tests to validate output captured from standard error instead of logger calls, including coverage for model selection and fallback behavior.

Signed-off-by: WilliamK112 <164879897+WilliamK112@users.noreply.github.com>
@copy-pr-bot

copy-pr-bot Bot commented Jun 23, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The plugin registration startup banner in register() is changed from emitting via api.logger.info to writing directly to process.stderr. Corresponding tests replace logger-based assertions with a process.stderr.write spy and updated banner content checks.

Changes

Banner output routed to stderr

Layer / File(s) Summary
Banner redirected to process.stderr
nemoclaw/src/index.ts
renderBox(bannerLines) output and surrounding blank lines are now emitted via process.stderr.write(line + '\n') instead of api.logger.info(...).
Tests updated for stderr assertions
nemoclaw/src/register.test.ts
Adds afterEach import and stderr capture helpers (mockStderrWrite, stderrOutput); wires stderr spying into beforeEach for the plugin registration and before_tool_call suites; replaces prior api.logger.info assertions with stderrOutput() checks for banner lines ("NemoClaw registered", "Endpoint", "Provider", "Model"); adds afterEach cleanup via vi.restoreAllMocks().

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~4 minutes

Poem

🐰 Hop hop, the banner took a wrong turn,
It cluttered stdout — quite a concern!
Now stderr's the home for the plugin's big shout,
No more init box leaking the agent reply out.
The rabbit grins wide: clean pipes all around! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title concisely and accurately summarizes the main change: redirecting the registration banner output to stderr instead of stdout.
Linked Issues check ✅ Passed The PR directly addresses issue #5654 by routing the registration banner to stderr instead of stdout, preventing stdout pollution in non-JSON mode.
Out of Scope Changes check ✅ Passed All changes are directly related to the objective of routing the registration banner to stderr; no unrelated modifications are present.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
nemoclaw/src/register.test.ts (1)

81-81: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Restore process.stderr.write after each test to prevent cross-test bleed.

vi.clearAllMocks() resets call history but does not restore spied implementations. Adding afterEach(() => vi.restoreAllMocks()) (or restoring stderrWrite directly) avoids leakage into other suites.

Suggested patch
 describe("plugin registration", () => {
   beforeEach(() => {
     vi.clearAllMocks();
     mockStderrWrite();
   });
+  afterEach(() => {
+    vi.restoreAllMocks();
+  });
@@
 describe("before_tool_call secret scanner hook (`#1233`)", () => {
   beforeEach(() => {
     vi.clearAllMocks();
     mockStderrWrite();
   });
+  afterEach(() => {
+    vi.restoreAllMocks();
+  });

Also applies to: 209-210

🤖 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 `@nemoclaw/src/register.test.ts` at line 81, The mockStderrWrite function call
spies on process.stderr.write but the spy is not being restored between tests,
which can cause state to leak from one test to another. Add an afterEach hook in
the test suite that calls vi.restoreAllMocks() to properly restore the original
implementations of spied functions after each test completes, ensuring no
cross-test contamination occurs.
🤖 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.

Nitpick comments:
In `@nemoclaw/src/register.test.ts`:
- Line 81: The mockStderrWrite function call spies on process.stderr.write but
the spy is not being restored between tests, which can cause state to leak from
one test to another. Add an afterEach hook in the test suite that calls
vi.restoreAllMocks() to properly restore the original implementations of spied
functions after each test completes, ensuring no cross-test contamination
occurs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7e1e9707-82ef-4363-87d5-7e7005ad92e2

📥 Commits

Reviewing files that changed from the base of the PR and between a9f31e4 and daad68c.

📒 Files selected for processing (2)
  • nemoclaw/src/index.ts
  • nemoclaw/src/register.test.ts

Signed-off-by: WilliamK112 <164879897+WilliamK112@users.noreply.github.com>
@wscurran wscurran added area: cli Command line interface, flags, terminal UX, or output bug-fix PR fixes a bug or regression labels Jun 23, 2026
@wscurran

Copy link
Copy Markdown
Contributor

✨ Thanks for routing the plugin registration banner to stderr to keep non-JSON agent passthrough stdout clean. This proposes a way to write the banner via process.stderr.write and updates plugin registration tests to capture stderr.


Related open issues:

@wscurran wscurran added the NV QA Bugs found by the NVIDIA QA Team label Jun 26, 2026
@cv cv added the v0.0.77 label Jul 8, 2026
@ericksoa ericksoa added v0.0.78 and removed v0.0.77 labels Jul 8, 2026

@cjagwani cjagwani left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed the exact head after the shared-test rerun: the registration banner is redirected to stderr, stdout remains machine-readable, and the focused regression coverage plus full CI are green.

@cjagwani

cjagwani commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Superseded by current-main replacement #6480, which preserves the banner-to-stderr fix, adds the non-JSON passthrough boundary coverage, and is green/approved at exact head 6b82a4d. Closing this stale duplicate so the release queue has one merge candidate.

@cjagwani cjagwani closed this Jul 8, 2026
cv added a commit that referenced this pull request Jul 8, 2026
<!-- markdownlint-disable MD041 -->
## Summary
Routes the in-sandbox NemoClaw registration banner to `stderr` so
non-JSON agent output on `stdout` remains machine-readable.
This is a current-main, GitHub-verified replacement for #5674 that
preserves the contributor's original authorship.

## Related Issue
Fixes #5654.

## Changes
- Write the plugin registration banner directly to `stderr` instead of
plugin info logs.
- Cover banner routing, live model rendering, mock restoration, and the
non-JSON passthrough stream boundary.
- Document the agent command's stdout/stderr contract.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [x] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Quality Gates
<!-- Check exactly one tests line and one docs line. Check other lines
when applicable. Add every requested justification or approval
reference. -->
- [x] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [ ] Tests not applicable — justification:
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification
<!-- Check each applicable item only when supported by the requested
evidence. Run targeted tests once per relevant change set and rerun
after later edits or hook autofixes that can affect the tested behavior.
Do not rerun hook-covered checks. -->
- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — command/result or justification: `npm
--prefix nemoclaw test -- src/register.test.ts` passed 24/24; `npx
vitest run --project cli
src/lib/actions/sandbox/agent/passthrough.test.ts` passed 38/38; plugin
and CLI builds passed.
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result:
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only)
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

`npm run docs` passed with zero errors and two pre-existing Fern
warnings.

---
<!-- DCO sign-off is required in this PR description, and every commit
must appear as Verified in GitHub. Run: git config user.name && git
config user.email -->
Signed-off-by: Carlos Villela <cvillela@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Updated agent startup so the NemoClaw registration banner is emitted
to standard error, avoiding interference with non-JSON agent replies on
standard output.
* **Documentation**
* Refreshed the command reference to clarify where the banner appears
during non-JSON runs.
* **Tests**
* Revised banner-related tests to capture and assert standard error
output, and added coverage to ensure standard output remains clean for
non-JSON replies.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: WilliamK112 <164879897+WilliamK112@users.noreply.github.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: WilliamK112 <164879897+WilliamK112@users.noreply.github.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary
Routes the in-sandbox NemoClaw registration banner to `stderr` so
non-JSON agent output on `stdout` remains machine-readable.
This is a current-main, GitHub-verified replacement for NVIDIA#5674 that
preserves the contributor's original authorship.

## Related Issue
Fixes NVIDIA#5654.

## Changes
- Write the plugin registration banner directly to `stderr` instead of
plugin info logs.
- Cover banner routing, live model rendering, mock restoration, and the
non-JSON passthrough stream boundary.
- Document the agent command's stdout/stderr contract.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [x] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Quality Gates
<!-- Check exactly one tests line and one docs line. Check other lines
when applicable. Add every requested justification or approval
reference. -->
- [x] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [ ] Tests not applicable — justification:
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification
<!-- Check each applicable item only when supported by the requested
evidence. Run targeted tests once per relevant change set and rerun
after later edits or hook autofixes that can affect the tested behavior.
Do not rerun hook-covered checks. -->
- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — command/result or justification: `npm
--prefix nemoclaw test -- src/register.test.ts` passed 24/24; `npx
vitest run --project cli
src/lib/actions/sandbox/agent/passthrough.test.ts` passed 38/38; plugin
and CLI builds passed.
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result:
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only)
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

`npm run docs` passed with zero errors and two pre-existing Fern
warnings.

---
<!-- DCO sign-off is required in this PR description, and every commit
must appear as Verified in GitHub. Run: git config user.name && git
config user.email -->
Signed-off-by: Carlos Villela <cvillela@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Updated agent startup so the NemoClaw registration banner is emitted
to standard error, avoiding interference with non-JSON agent replies on
standard output.
* **Documentation**
* Refreshed the command reference to clarify where the banner appears
during non-JSON runs.
* **Tests**
* Revised banner-related tests to capture and assert standard error
output, and added coverage to ensure standard output remains clean for
non-JSON replies.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: WilliamK112 <164879897+WilliamK112@users.noreply.github.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: WilliamK112 <164879897+WilliamK112@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli Command line interface, flags, terminal UX, or output bug-fix PR fixes a bug or regression NV QA Bugs found by the NVIDIA QA Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Ubuntu 26.04][CLI&UX] nemoclaw <name> agent writes "[plugins] NemoClaw registered" init box to stdout in non-json mode, polluting piped output

5 participants