Skip to content

Commit 1a45d28

Browse files
Junior00619kjw3
andauthored
fix(cli): show live gateway model/provider in list and status commands (#1041)
nemoclaw list and the global status display only read model/provider from the local registry, which stores null when inference is configured after onboarding (e.g. via openshell inference set). This makes both commands show 'unknown' even when the gateway has a configured inference route. Query openshell inference get once per invocation and prefer the live values over stale registry entries, matching the existing behavior of the per-sandbox status command. Fixes #986 Co-authored-by: KJ <[email protected]>
1 parent 4487598 commit 1a45d28

2 files changed

Lines changed: 110 additions & 4 deletions

File tree

bin/nemoclaw.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -519,12 +519,15 @@ function showStatus() {
519519
// Show sandbox registry
520520
const { sandboxes, defaultSandbox } = registry.listSandboxes();
521521
if (sandboxes.length > 0) {
522+
const live = parseGatewayInference(
523+
captureOpenshell(["inference", "get"], { ignoreError: true }).output
524+
);
522525
console.log("");
523526
console.log(" Sandboxes:");
524527
for (const sb of sandboxes) {
525528
const def = sb.name === defaultSandbox ? " *" : "";
526-
const model = sb.model ? ` (${sb.model})` : "";
527-
console.log(` ${sb.name}${def}${model}`);
529+
const model = (live && live.model) || sb.model;
530+
console.log(` ${sb.name}${def}${model ? ` (${model})` : ""}`);
528531
}
529532
console.log("");
530533
}
@@ -542,12 +545,17 @@ function listSandboxes() {
542545
return;
543546
}
544547

548+
// Query live gateway inference once; prefer it over stale registry values.
549+
const live = parseGatewayInference(
550+
captureOpenshell(["inference", "get"], { ignoreError: true }).output
551+
);
552+
545553
console.log("");
546554
console.log(" Sandboxes:");
547555
for (const sb of sandboxes) {
548556
const def = sb.name === defaultSandbox ? " *" : "";
549-
const model = sb.model || "unknown";
550-
const provider = sb.provider || "unknown";
557+
const model = (live && live.model) || sb.model || "unknown";
558+
const provider = (live && live.provider) || sb.provider || "unknown";
551559
const gpu = sb.gpuEnabled ? "GPU" : "CPU";
552560
const presets = sb.policies && sb.policies.length > 0 ? sb.policies.join(", ") : "none";
553561
console.log(` ${sb.name}${def}`);

test/cli.test.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,3 +746,101 @@ describe("CLI dispatch", () => {
746746
expect(statusResult.out.includes("Start the gateway again")).toBeTruthy();
747747
}, 25000);
748748
});
749+
750+
describe("list shows live gateway inference", () => {
751+
it("prefers live inference model/provider over stale registry values", () => {
752+
const home = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-cli-list-live-"));
753+
const localBin = path.join(home, "bin");
754+
const registryDir = path.join(home, ".nemoclaw");
755+
fs.mkdirSync(localBin, { recursive: true });
756+
fs.mkdirSync(registryDir, { recursive: true });
757+
// Registry has no model/provider (mimics post-onboard before inference setup)
758+
fs.writeFileSync(
759+
path.join(registryDir, "sandboxes.json"),
760+
JSON.stringify({
761+
sandboxes: {
762+
test: {
763+
name: "test",
764+
model: null,
765+
provider: null,
766+
gpuEnabled: true,
767+
policies: ["pypi", "npm"],
768+
},
769+
},
770+
defaultSandbox: "test",
771+
}),
772+
{ mode: 0o600 }
773+
);
774+
// Stub openshell: inference get returns live provider/model
775+
fs.writeFileSync(
776+
path.join(localBin, "openshell"),
777+
[
778+
"#!/usr/bin/env bash",
779+
"if [ \"$1\" = \"inference\" ] && [ \"$2\" = \"get\" ]; then",
780+
" echo 'Gateway inference:'",
781+
" echo ' Provider: nvidia-prod'",
782+
" echo ' Model: nvidia/nemotron-3-super-120b-a12b'",
783+
" echo ' Version: 1'",
784+
" exit 0",
785+
"fi",
786+
"exit 0",
787+
].join("\n"),
788+
{ mode: 0o755 }
789+
);
790+
791+
const r = runWithEnv("list", {
792+
HOME: home,
793+
PATH: `${localBin}:${process.env.PATH || ""}`,
794+
});
795+
796+
expect(r.code).toBe(0);
797+
expect(r.out).toContain("nvidia/nemotron-3-super-120b-a12b");
798+
expect(r.out).toContain("nvidia-prod");
799+
expect(r.out).not.toContain("unknown");
800+
});
801+
802+
it("falls back to registry values when openshell inference get fails", () => {
803+
const home = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-cli-list-fallback-"));
804+
const localBin = path.join(home, "bin");
805+
const registryDir = path.join(home, ".nemoclaw");
806+
fs.mkdirSync(localBin, { recursive: true });
807+
fs.mkdirSync(registryDir, { recursive: true });
808+
fs.writeFileSync(
809+
path.join(registryDir, "sandboxes.json"),
810+
JSON.stringify({
811+
sandboxes: {
812+
test: {
813+
name: "test",
814+
model: "llama3.2:1b",
815+
provider: "ollama-local",
816+
gpuEnabled: false,
817+
policies: [],
818+
},
819+
},
820+
defaultSandbox: "test",
821+
}),
822+
{ mode: 0o600 }
823+
);
824+
// Stub openshell: inference get fails
825+
fs.writeFileSync(
826+
path.join(localBin, "openshell"),
827+
[
828+
"#!/usr/bin/env bash",
829+
"if [ \"$1\" = \"inference\" ] && [ \"$2\" = \"get\" ]; then",
830+
" exit 1",
831+
"fi",
832+
"exit 0",
833+
].join("\n"),
834+
{ mode: 0o755 }
835+
);
836+
837+
const r = runWithEnv("list", {
838+
HOME: home,
839+
PATH: `${localBin}:${process.env.PATH || ""}`,
840+
});
841+
842+
expect(r.code).toBe(0);
843+
expect(r.out).toContain("llama3.2:1b");
844+
expect(r.out).toContain("ollama-local");
845+
});
846+
});

0 commit comments

Comments
 (0)