Skip to content

fix(plugin): show actual configured model in banner (Closes #24) - #1819

Merged
cv merged 3 commits into
NVIDIA:mainfrom
WuKongAI-CMU:fix/dynamic-model-banner-v2
Apr 21, 2026
Merged

fix(plugin): show actual configured model in banner (Closes #24)#1819
cv merged 3 commits into
NVIDIA:mainfrom
WuKongAI-CMU:fix/dynamic-model-banner-v2

Conversation

@WuKongAI-CMU

@WuKongAI-CMU WuKongAI-CMU commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

Summary

When the onboard config file is not available (e.g. when running inside the sandbox), the plugin banner in `nemoclaw/src/index.ts` hardcodes the model as `nvidia/nemotron-3-super-120b-a12b` and the endpoint as `build.nvidia.com` regardless of what is actually configured in OpenShell.

This PR queries the live OpenShell inference state via `openshell inference get --json` as a fallback before resorting to hardcoded defaults. The probe has a 3-second timeout and falls back cleanly to the existing defaults if anything goes wrong.

Closes #24.

Changes

  • `nemoclaw/src/index.ts` — add `probeOpenShellInference()` helper and wire it into banner resolution after onboard config lookup, before hardcoded defaults

Test plan

  • Minimal diff, existing defaults preserved as final fallback
  • 3s timeout prevents banner from hanging on a slow/broken openshell binary
  • No new runtime dependencies (uses stdlib `node:child_process`)

(Resubmitting — prior PR #1816 was auto-closed by the 10-PR-cap check when our open PR count briefly exceeded the limit; we're now under the cap.)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved configuration resolution for model provider, endpoint, and model: the app now prefers onboard settings, probes live inference state to fill missing values, and falls back to defaults for more reliable initialization and registration.
  • Tests
    • Added test coverage verifying fallback to probed inference values and confirming probe details are logged during registration.

Signed-off-by: Intern Dev dev@wukongai.io

When the onboard config file is not available (e.g. inside the sandbox),
the plugin banner hardcodes the model as nvidia/nemotron-3-super-120b-a12b
and the endpoint as build.nvidia.com regardless of what is actually
configured in OpenShell.

Query the live OpenShell inference state via `openshell inference get
--json` as a fallback before resorting to hardcoded defaults. The probe
has a 3-second timeout and falls back to the existing defaults if
anything goes wrong.

Closes NVIDIA#24
@coderabbitai

coderabbitai Bot commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 31399376-708a-42a5-b41a-0462f78f38f1

📥 Commits

Reviewing files that changed from the base of the PR and between a9a973e and ea9aa8f.

📒 Files selected for processing (2)
  • nemoclaw/src/index.ts
  • nemoclaw/src/register.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • nemoclaw/src/register.test.ts

📝 Walkthrough

Walkthrough

Adds a synchronous probe of OpenShell inference state and updates provider/model resolution so registration uses onboard config first, then the probe, then original hardcoded defaults; tests were added to validate the probe-driven fallback when onboard config is absent.

Changes

Cohort / File(s) Summary
Index / resolution logic
nemoclaw/src/index.ts
Added probeOpenShellInference() (runs openshell inference get --json with a 3s timeout). activeModelEntries() and registeredProviderForConfig() now accept an optional fallback model. register() was reworked to source banner/provider/model from onboard → probe → hardcoded defaults and passes probed model into provider registration.
Tests
nemoclaw/src/register.test.ts
Mocked node:child_process.execFileSync, reset mock in beforeEach(), and added a test for the "onboard unavailable" path that forces a probed JSON response and asserts register(api) registers the probed model and logs probed Endpoint/Provider/Model.

Sequence Diagram(s)

sequenceDiagram
    participant Register as Register()
    participant Onboard as OnboardConfig
    participant Probe as OpenShell CLI (execFileSync)
    participant Defaults as HardcodedDefaults
    participant Registry as ProviderRegistry

    Register->>Onboard: read bannerEndpoint / bannerProvider / bannerModel
    alt onboard has all values
        Register->>Registry: register using onboard values
    else missing any value
        Register->>Probe: execFileSync("openshell inference get --json") (3s)
        Probe-->>Register: { endpoint, provider, model } or error
        alt probe supplies missing values
            Register->>Registry: register using onboard + probed values
        else
            Register->>Defaults: use hardcoded defaults
            Defaults-->>Register: { endpoint, provider, model }
            Register->>Registry: register using onboard + defaults
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I probed the shell where models sleep,
I peeked and parsed what secrets keep.
Onboard first, then live we see,
If silence stays, old names agree.
A hop, a log — the banner speaks true. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: fixing the display of the actual configured model in the plugin banner instead of a hardcoded default.
Linked Issues check ✅ Passed The PR implements all acceptance criteria from issue #24: probes actual OpenShell configuration, displays configured provider/model in banner, includes tests for non-default providers, and preserves fallback behavior.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the banner model display issue: probeOpenShellInference() helper, banner resolution logic updates, and corresponding tests for the new functionality.

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

@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.

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
nemoclaw/src/index.ts (1)

272-275: ⚠️ Potential issue | 🟠 Major

Resolve the effective model before registerProvider().

The probe only updates banner strings after registerProvider() has already been called. When onboardCfg is missing, activeModelEntries() still publishes the baked-in catalog, so the registered provider/UI can disagree with the banner and with the live OpenShell model.

Also applies to: 283-290

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nemoclaw/src/index.ts` around lines 272 - 275, The provider is being
registered before the effective model/catalog is resolved, so the UI banner and
registered provider can disagree; before calling
api.registerProvider(registeredProviderForConfig(onboardCfg,
providerCredentialEnv)) ensure the effective model is resolved by invoking the
same resolution path used by the probe—e.g., call activeModelEntries() (or
otherwise trigger the probe/model resolution logic) right after
loadOnboardConfig() and before computing registeredProviderForConfig so the
banner/catalog are up-to-date when api.registerProvider runs (also apply this
ordering fix to the similar block around the code at lines 283–290).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@nemoclaw/src/index.ts`:
- Around line 25-40: probeOpenShellInference currently only returns endpoint and
model so callers (banner logic) always fall back to "NVIDIA Endpoints"; modify
probeOpenShellInference to also return the provider string by reading
parsed.provider (e.g., return { provider: parsed.provider ?? parsed.endpoint ??
"", endpoint: parsed.endpoint ?? parsed.provider ?? "", model: parsed.model ??
"" }) and update any banner/display code that uses probeOpenShellInference() to
prefer the returned provider when present (instead of hardcoding "NVIDIA
Endpoints"), e.g., use the provider value to construct the banner label.
- Around line 25-44: Add a Vitest unit test in the existing register.test.ts
that mocks node:child_process execFileSync to return a JSON string with
provider, model, and/or endpoint (e.g.
{"provider":"custom","model":"gpt-x","endpoint":"https://api"}), call
probeOpenShellInference and assert it returns the probed non-default
provider/model/endpoint; also add an integration-style assertion that the code
path which consumes probeOpenShellInference (the registration logic referenced
around probeOpenShellInference and the similar block at lines ~283-290) uses
those values instead of defaults. Use Vitest's vi.mock or vi.spyOn to stub
execFileSync, ensure you restore/reset the mock after the test, and cover both
provider->endpoint fallback and explicit endpoint cases.

---

Outside diff comments:
In `@nemoclaw/src/index.ts`:
- Around line 272-275: The provider is being registered before the effective
model/catalog is resolved, so the UI banner and registered provider can
disagree; before calling
api.registerProvider(registeredProviderForConfig(onboardCfg,
providerCredentialEnv)) ensure the effective model is resolved by invoking the
same resolution path used by the probe—e.g., call activeModelEntries() (or
otherwise trigger the probe/model resolution logic) right after
loadOnboardConfig() and before computing registeredProviderForConfig so the
banner/catalog are up-to-date when api.registerProvider runs (also apply this
ordering fix to the similar block around the code at lines 283–290).
🪄 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: CHILL

Plan: Pro

Run ID: cef3faf3-a982-4de0-b744-e941f6c51da9

📥 Commits

Reviewing files that changed from the base of the PR and between d4aac4c and dbd9b9f.

📒 Files selected for processing (1)
  • nemoclaw/src/index.ts

Comment thread nemoclaw/src/index.ts Outdated
Comment thread nemoclaw/src/index.ts Outdated
@wscurran

Copy link
Copy Markdown
Contributor

@cjagwani cjagwani self-assigned this Apr 14, 2026
@cjagwani

cjagwani commented Apr 15, 2026

Copy link
Copy Markdown
Collaborator

Good fix @WuKongAI-CMU — the probe fallback chain is clean and the 3-second timeout is well-chosen. One gap to address before merge:

Provider still hardcoded. When onboardCfg is missing (inside the sandbox), bannerProvider falls back to "NVIDIA Endpoints" even if the probe returns Ollama or OpenAI. The model and endpoint are now dynamic but the provider line stays wrong.

CodeRabbit flagged this too — here's the minimal fix:

-function probeOpenShellInference(): { endpoint: string; model: string } {
+function probeOpenShellInference(): { endpoint: string; provider: string; model: string } {
   // ...
   return {
     endpoint: parsed.endpoint ?? parsed.provider ?? "",
+    provider: parsed.provider ?? "",
     model: parsed.model ?? "",
   };
   // catch:
-  return { endpoint: "", model: "" };
+  return { endpoint: "", provider: "", model: "" };
 }

-  const bannerProvider = onboardCfg ? describeOnboardProvider(onboardCfg) : "NVIDIA Endpoints";
+  let bannerProvider = onboardCfg ? describeOnboardProvider(onboardCfg) : "";

-  if (!bannerEndpoint || !bannerModel) {
+  if (!bannerEndpoint || !bannerProvider || !bannerModel) {
     const probed = probeOpenShellInference();
     if (!bannerEndpoint) bannerEndpoint = probed.endpoint;
+    if (!bannerProvider) bannerProvider = probed.provider;
     if (!bannerModel) bannerModel = probed.model;
   }
+  if (!bannerProvider) bannerProvider = "NVIDIA Endpoints";

This way Ollama users see "Ollama" instead of "NVIDIA Endpoints" in the banner.

Also: DCO — add Signed-off-by: Your Name <your@email.com> to the PR description body.

The in-sandbox plugin can lack the onboard config file, so the banner and registered provider catalog need to derive provider/model identity from the live OpenShell inference probe before falling back to NVIDIA defaults.

Constraint: OpenShell probe is the only live source available inside sandbox execution.\nRejected: Keep provider defaulted to NVIDIA Endpoints | it leaves Ollama/OpenAI users with an incorrect banner.\nConfidence: high\nScope-risk: narrow\nTested: npm test -- nemoclaw/src/register.test.ts\nTested: npm run check --prefix nemoclaw\nTested: git diff --check\nSigned-off-by: Intern Dev <dev@wukongai.io>
@cv cv added the v0.0.18 label Apr 16, 2026
@ericksoa ericksoa added v0.0.19 and removed v0.0.18 labels Apr 17, 2026
@WuKongAI-CMU

Copy link
Copy Markdown
Contributor Author

Confirmed the requested follow-up is already in the latest head (a9a973eb): probeOpenShellInference() now returns provider, the banner uses the probed provider before falling back to NVIDIA Endpoints, and the registered provider catalog uses the probed model when onboard config is unavailable. The PR body also includes Signed-off-by: Intern Dev <dev@wukongai.io>.

Verification:

  • npm test -- nemoclaw/src/register.test.ts -> 1 file passed, 8 tests passed
  • cd nemoclaw && npm run build
  • git diff --check

@ericksoa ericksoa added v0.0.20 and removed v0.0.19 labels Apr 18, 2026
@cv cv added v0.0.21 and removed v0.0.20 labels Apr 20, 2026

@cv cv 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.

Looks good to me.

  • banner now prefers onboard config, then live openshell inference get --json, then hardcoded defaults
  • registered model catalog also reflects the probed active model when onboard config is unavailable
  • regression coverage added for a non-default provider/model path

I also re-ran a local targeted check on the PR branch:

  • npx vitest run nemoclaw/src/register.test.ts
  • cd nemoclaw && npm run check

@cv cv added v0.0.22 and removed v0.0.21 labels Apr 21, 2026
@cv
cv merged commit ebd7848 into NVIDIA:main Apr 21, 2026
1 check passed
@miyoungc miyoungc mentioned this pull request Apr 22, 2026
13 tasks
miyoungc added a commit that referenced this pull request Apr 22, 2026
## Summary

Bumps the published doc version to `0.0.22` and documents the
user-visible CLI behavior changes to `nemoclaw <name> connect` that
landed since v0.0.21. Drafted via the `nemoclaw-contributor-update-docs`
skill against commits in `v0.0.21..origin/main`, filtered through
`docs/.docs-skip`.

## Changes

- **`docs/project.json`** and **`docs/versions1.json`**: bump the
published version from `0.0.20` to `0.0.22`; insert a `0.0.21` entry
into the version list so the history stays contiguous.
- **`docs/reference/commands.md`** → `nemoclaw <name> connect`: document
two new behaviors.
- Readiness poll with `NEMOCLAW_CONNECT_TIMEOUT` (integer seconds;
default `120`) that replaces the silent hang when the sandbox is not yet
`Ready` — right after onboarding, while the 2.4 GB image is still
pulling (#466).
- Post-connect hint is now agent-aware, names the correct TUI command
for the sandbox's agent, and tells you to use `/exit` to leave the chat
before `exit` returns you to the host shell (#2080).

Feature PRs that shipped their own docs in the same commit are
intentionally not re-documented here:

- `channels list/add/remove` (#2139) — command reference and the
"`openclaw channels` blocked inside the sandbox" troubleshooting entry
landed with the feature.
- `nemoclaw gc` (#2176) — documented as part of the destroy/rebuild
image cleanup PR.

Skipped per `docs/.docs-skip`:

- `e6bad533 fix(shields): verify config lock and fail hard on re-lock
failure (#2066)` — matched `skip-features: src/lib/shields.ts`.

Other commits in the range (#2141 OpenShell version bump, #1819 plugin
banner live inference probe, #2085 / #2146 Slack Socket Mode fixes,
#2110 axios proxy fix, #1818 NIM curl timeouts, #1824 onboard gateway
bootstrap recovery, and assorted CI / test / install plumbing) are
internal behavior refinements with no doc-relevant surface change.

## Type of Change

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

## Verification

- [x] `npx prek run --all-files` passes for the modified files via the
pre-commit hook, including `Regenerate agent skills from docs` (source ↔
generated parity confirmed)
- [ ] `npm test` passes — skipped; the one pre-existing
`test/cli.test.ts > unknown command exits 1` failure on `origin/main` is
unrelated to these markdown/JSON-only changes
- [ ] Tests added or updated for new or changed behavior — n/a, doc-only
- [x] No secrets, API keys, or credentials committed
- [x] Docs updated for user-facing behavior changes
- [ ] `make docs` builds without warnings (doc changes only) — not run
locally
- [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)
— n/a, no new pages

## AI Disclosure

- [x] AI-assisted — tool: Claude Code

---
Signed-off-by: Miyoung Choi <miyoungc@nvidia.com>

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

* **New Features**
* `connect` now displays the sandbox phase while waiting for readiness
and honors a configurable timeout via NEMOCLAW_CONNECT_TIMEOUT (default
120s).
* TTY hints are agent-aware and instruct using `/exit` before returning
to the host shell.

* **Documentation**
  * Command docs updated to describe polling, timeout, and TTY guidance.
* Project/docs metadata updated for versions 0.0.21 and 0.0.22 (package
version bumped to 0.0.22).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@wscurran wscurran added the area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery label Jun 3, 2026
@wscurran wscurran added bug-fix PR fixes a bug or regression and removed OpenShell labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery bug-fix PR fixes a bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix hardcoded model identity shown by the in-sandbox plugin/banner so it reflects the actual configured inference provider

6 participants