Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions bin/lib/local-inference.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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." };
Expand All @@ -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." };
Expand Down Expand Up @@ -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") {
Expand All @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions bin/lib/nim.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
14 changes: 7 additions & 7 deletions bin/lib/onboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)",
});
}

Expand Down Expand Up @@ -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);
Expand All @@ -662,15 +662,15 @@ 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);
} else {
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";
}
Expand Down
10 changes: 5 additions & 5 deletions test/local-inference.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
);
});

Expand All @@ -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", () => {
Expand All @@ -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", () => {
Expand Down Expand Up @@ -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"/);
});

Expand Down
4 changes: 2 additions & 2 deletions test/onboard-selection.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading