From abc1036f7c562a05f158053ed8593f97930ce3aa Mon Sep 17 00:00:00 2001 From: dumko2001 Date: Tue, 17 Mar 2026 15:07:13 +0530 Subject: [PATCH 1/2] fix(onboard): use 127.0.0.1 instead of localhost for local inference detection --- bin/lib/onboard.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/lib/onboard.js b/bin/lib/onboard.js index d1b7e5791cd..0e4d28c2ec2 100644 --- a/bin/lib/onboard.js +++ b/bin/lib/onboard.js @@ -527,8 +527,8 @@ async function setupNim(sandboxName, gpu) { // Detect local inference options const hasOllama = !!runCapture("command -v ollama", { ignoreError: true }); - const ollamaRunning = !!runCapture("curl -sf http://localhost:11434/api/tags 2>/dev/null", { ignoreError: true }); - const vllmRunning = !!runCapture("curl -sf http://localhost:8000/v1/models 2>/dev/null", { ignoreError: true }); + const ollamaRunning = !!runCapture("curl -sf http://127.0.0.1:11434/api/tags 2>/dev/null", { ignoreError: true }); + const vllmRunning = !!runCapture("curl -sf http://127.0.0.1:8000/v1/models 2>/dev/null", { ignoreError: true }); const requestedProvider = isNonInteractive() ? getNonInteractiveProvider() : null; const requestedModel = isNonInteractive() ? getNonInteractiveModel(requestedProvider || "cloud") : null; // Build options list — only show local options with NEMOCLAW_EXPERIMENTAL=1 @@ -546,14 +546,14 @@ async function setupNim(sandboxName, gpu) { options.push({ key: "ollama", label: - `Local Ollama (localhost:11434)${ollamaRunning ? " — running" : ""}` + + `Local Ollama (127.0.0.1:11434)${ollamaRunning ? " — running" : ""}` + (ollamaRunning ? " (suggested)" : ""), }); } if (EXPERIMENTAL && vllmRunning) { options.push({ key: "vllm", - label: "Existing vLLM instance (localhost:8000) — running [experimental] (suggested)", + label: "Existing vLLM instance (127.0.0.1:8000) — running [experimental] (suggested)", }); } From 9d2653cfc8a7f69b379acd05fa9716bd9be00508 Mon Sep 17 00:00:00 2001 From: dumko2001 Date: Sun, 22 Mar 2026 19:15:28 +0530 Subject: [PATCH 2/2] fix(onboard): align local inference health checks to 127.0.0.1 and fix tests --- bin/lib/local-inference.js | 16 ++++++++-------- bin/lib/nim.js | 4 ++-- bin/lib/onboard.js | 6 +++--- test/local-inference.test.js | 10 +++++----- test/onboard-selection.test.js | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/bin/lib/local-inference.js b/bin/lib/local-inference.js index 1065a70e321..fc8bd04df20 100644 --- a/bin/lib/local-inference.js +++ b/bin/lib/local-inference.js @@ -21,9 +21,9 @@ function getLocalProviderBaseUrl(provider) { function getLocalProviderHealthCheck(provider) { switch (provider) { case "vllm-local": - return "curl -sf http://localhost:8000/v1/models 2>/dev/null"; + return "curl -sf http://127.0.0.1:8000/v1/models 2>/dev/null"; case "ollama-local": - return "curl -sf http://localhost:11434/api/tags 2>/dev/null"; + return "curl -sf http://127.0.0.1:11434/api/tags 2>/dev/null"; default: return null; } @@ -52,12 +52,12 @@ function validateLocalProvider(provider, runCapture) { case "vllm-local": return { ok: false, - message: "Local vLLM was selected, but nothing is responding on http://localhost:8000.", + message: "Local vLLM was selected, but nothing is responding on http://127.0.0.1:8000.", }; case "ollama-local": return { ok: false, - message: "Local Ollama was selected, but nothing is responding on http://localhost:11434.", + message: "Local Ollama was selected, but nothing is responding on http://127.0.0.1:11434.", }; default: return { ok: false, message: "The selected local inference provider is unavailable." }; @@ -79,13 +79,13 @@ function validateLocalProvider(provider, runCapture) { return { ok: false, message: - "Local vLLM is responding on localhost, but containers cannot reach http://host.openshell.internal:8000. Ensure the server is reachable from containers, not only from the host shell.", + "Local vLLM is responding on 127.0.0.1, but containers cannot reach http://host.openshell.internal:8000. Ensure the server is reachable from containers, not only from the host shell.", }; case "ollama-local": return { ok: false, message: - "Local Ollama is responding on localhost, but containers cannot reach http://host.openshell.internal:11434. Ensure Ollama listens on 0.0.0.0:11434 instead of 127.0.0.1 so sandboxes can reach it.", + "Local Ollama is responding on 127.0.0.1, but containers cannot reach http://host.openshell.internal:11434. Ensure Ollama listens on 0.0.0.0:11434 instead of 127.0.0.1 so sandboxes can reach it.", }; default: return { ok: false, message: "The selected local inference provider is unavailable from containers." }; @@ -123,7 +123,7 @@ function getOllamaWarmupCommand(model, keepAlive = "15m") { stream: false, keep_alive: keepAlive, }); - return `nohup curl -s http://localhost:11434/api/generate -H 'Content-Type: application/json' -d ${shellQuote(payload)} >/dev/null 2>&1 &`; + return `nohup curl -s http://127.0.0.1:11434/api/generate -H 'Content-Type: application/json' -d ${shellQuote(payload)} >/dev/null 2>&1 &`; } function getOllamaProbeCommand(model, timeoutSeconds = 120, keepAlive = "15m") { @@ -133,7 +133,7 @@ function getOllamaProbeCommand(model, timeoutSeconds = 120, keepAlive = "15m") { stream: false, keep_alive: keepAlive, }); - return `curl -sS --max-time ${timeoutSeconds} http://localhost:11434/api/generate -H 'Content-Type: application/json' -d ${shellQuote(payload)} 2>/dev/null`; + return `curl -sS --max-time ${timeoutSeconds} http://127.0.0.1:11434/api/generate -H 'Content-Type: application/json' -d ${shellQuote(payload)} 2>/dev/null`; } function validateOllamaModel(model, runCapture) { diff --git a/bin/lib/nim.js b/bin/lib/nim.js index 548b2db2347..8528f22305a 100644 --- a/bin/lib/nim.js +++ b/bin/lib/nim.js @@ -152,7 +152,7 @@ function waitForNimHealth(port = 8000, timeout = 300) { while ((Date.now() - start) / 1000 < timeout) { try { - const result = runCapture(`curl -sf http://localhost:${safePort}/v1/models`, { + const result = runCapture(`curl -sf http://127.0.0.1:${safePort}/v1/models`, { ignoreError: true, }); if (result) { @@ -186,7 +186,7 @@ function nimStatus(sandboxName) { let healthy = false; if (state === "running") { - const health = runCapture(`curl -sf http://localhost:8000/v1/models 2>/dev/null`, { + const health = runCapture(`curl -sf http://127.0.0.1:8000/v1/models 2>/dev/null`, { ignoreError: true, }); healthy = !!health; diff --git a/bin/lib/onboard.js b/bin/lib/onboard.js index 0e4d28c2ec2..f2f2858ab7b 100644 --- a/bin/lib/onboard.js +++ b/bin/lib/onboard.js @@ -649,7 +649,7 @@ async function setupNim(sandboxName, gpu) { run("OLLAMA_HOST=0.0.0.0:11434 ollama serve > /dev/null 2>&1 &", { ignoreError: true }); sleep(2); } - console.log(" ✓ Using Ollama on localhost:11434"); + console.log(" ✓ Using Ollama on 127.0.0.1:11434"); provider = "ollama-local"; if (isNonInteractive()) { model = requestedModel || getDefaultOllamaModel(runCapture); @@ -662,7 +662,7 @@ async function setupNim(sandboxName, gpu) { console.log(" Starting Ollama..."); run("OLLAMA_HOST=0.0.0.0:11434 ollama serve > /dev/null 2>&1 &", { ignoreError: true }); sleep(2); - console.log(" ✓ Using Ollama on localhost:11434"); + console.log(" ✓ Using Ollama on 127.0.0.1:11434"); provider = "ollama-local"; if (isNonInteractive()) { model = requestedModel || getDefaultOllamaModel(runCapture); @@ -670,7 +670,7 @@ async function setupNim(sandboxName, gpu) { model = await promptOllamaModel(); } } else if (selected.key === "vllm") { - console.log(" ✓ Using existing vLLM on localhost:8000"); + console.log(" ✓ Using existing vLLM on 127.0.0.1:8000"); provider = "vllm-local"; model = "vllm-local"; } diff --git a/test/local-inference.test.js b/test/local-inference.test.js index 5b77ee2f7ad..f7eaa1755ca 100644 --- a/test/local-inference.test.js +++ b/test/local-inference.test.js @@ -37,7 +37,7 @@ describe("local inference helpers", () => { it("returns the expected health check command for ollama-local", () => { assert.equal( getLocalProviderHealthCheck("ollama-local"), - "curl -sf http://localhost:11434/api/tags 2>/dev/null", + "curl -sf http://127.0.0.1:11434/api/tags 2>/dev/null", ); }); @@ -61,7 +61,7 @@ describe("local inference helpers", () => { it("returns a clear error when ollama-local is unavailable", () => { const result = validateLocalProvider("ollama-local", () => ""); assert.equal(result.ok, false); - assert.match(result.message, /http:\/\/localhost:11434/); + assert.match(result.message, /http:\/\/127\.0\.0\.1:11434/); }); it("returns a clear error when ollama-local is not reachable from containers", () => { @@ -78,7 +78,7 @@ describe("local inference helpers", () => { it("returns a clear error when vllm-local is unavailable", () => { const result = validateLocalProvider("vllm-local", () => ""); assert.equal(result.ok, false); - assert.match(result.message, /http:\/\/localhost:8000/); + assert.match(result.message, /http:\/\/127\.0\.0\.1:8000/); }); it("parses model names from ollama list output", () => { @@ -121,14 +121,14 @@ describe("local inference helpers", () => { it("builds a background warmup command for ollama models", () => { const command = getOllamaWarmupCommand("nemotron-3-nano:30b"); - assert.match(command, /^nohup curl -s http:\/\/localhost:11434\/api\/generate /); + assert.match(command, /^nohup curl -s http:\/\/127\.0\.0\.1:11434\/api\/generate /); assert.match(command, /"model":"nemotron-3-nano:30b"/); assert.match(command, /"keep_alive":"15m"/); }); it("builds a foreground probe command for ollama models", () => { const command = getOllamaProbeCommand("nemotron-3-nano:30b"); - assert.match(command, /^curl -sS --max-time 120 http:\/\/localhost:11434\/api\/generate /); + assert.match(command, /^curl -sS --max-time 120 http:\/\/127\.0\.0\.1:11434\/api\/generate /); assert.match(command, /"model":"nemotron-3-nano:30b"/); }); diff --git a/test/onboard-selection.test.js b/test/onboard-selection.test.js index 9000943ba2f..cb1d45d65b2 100644 --- a/test/onboard-selection.test.js +++ b/test/onboard-selection.test.js @@ -34,9 +34,9 @@ credentials.prompt = async (message) => { credentials.ensureApiKey = async () => {}; runner.runCapture = (command) => { if (command.includes("command -v ollama")) return "/usr/bin/ollama"; - if (command.includes("localhost:11434/api/tags")) return JSON.stringify({ models: [{ name: "nemotron-3-nano:30b" }] }); + if (command.includes("127.0.0.1:11434/api/tags")) return JSON.stringify({ models: [{ name: "nemotron-3-nano:30b" }] }); if (command.includes("ollama list")) return "nemotron-3-nano:30b abc 24 GB now\\nqwen3:32b def 20 GB now"; - if (command.includes("localhost:8000/v1/models")) return ""; + if (command.includes("127.0.0.1:8000/v1/models")) return ""; return ""; }; registry.updateSandbox = (_name, update) => updates.push(update);