diff --git a/bin/lib/onboard.js b/bin/lib/onboard.js index 23f19b01a..709c3dc51 100644 --- a/bin/lib/onboard.js +++ b/bin/lib/onboard.js @@ -221,10 +221,10 @@ function getNonInteractiveProvider() { const providerKey = (process.env.NEMOCLAW_PROVIDER || "").trim().toLowerCase(); if (!providerKey) return null; - const validProviders = new Set(["cloud", "ollama", "vllm", "nim"]); + const validProviders = new Set(["cloud", "ollama", "vllm", "nim", "dynamo"]); if (!validProviders.has(providerKey)) { console.error(` Unsupported NEMOCLAW_PROVIDER: ${providerKey}`); - console.error(" Valid values: cloud, ollama, vllm, nim"); + console.error(" Valid values: cloud, ollama, vllm, nim, dynamo"); process.exit(1); } @@ -473,6 +473,22 @@ async function setupNim(sandboxName, gpu) { const vllmRunning = !!runCapture("curl -sf http://localhost:8000/v1/models 2>/dev/null", { ignoreError: true }); const requestedProvider = isNonInteractive() ? getNonInteractiveProvider() : null; const requestedModel = isNonInteractive() ? getNonInteractiveModel(requestedProvider || "cloud") : null; + + // Non-interactive Dynamo provider: handle before the interactive options flow + if (isNonInteractive() && requestedProvider === "dynamo") { + const dynamoEndpoint = (process.env.NEMOCLAW_DYNAMO_ENDPOINT || "").trim(); + if (!dynamoEndpoint) { + console.error(" NEMOCLAW_DYNAMO_ENDPOINT is required when NEMOCLAW_PROVIDER=dynamo."); + process.exit(1); + } + console.log(` [non-interactive] Using Dynamo provider`); + + provider = "dynamo"; + model = (process.env.NEMOCLAW_DYNAMO_MODEL || "").trim() || "dynamo"; + registry.updateSandbox(sandboxName, { model, provider, nimContainer }); + return { model, provider }; + } + // Build options list — only show local options with NEMOCLAW_EXPERIMENTAL=1 const options = []; if (EXPERIMENTAL && gpu && gpu.nimCapable) { @@ -645,7 +661,23 @@ async function setupNim(sandboxName, gpu) { async function setupInference(sandboxName, model, provider) { step(5, 7, "Setting up inference provider"); - if (provider === "nvidia-nim") { + if (provider === "dynamo") { + // Dynamo: external vLLM endpoint (e.g., K8s service) + const dynamoEndpoint = process.env.NEMOCLAW_DYNAMO_ENDPOINT; + // Use shellQuote for shell-safe escaping of the endpoint URL + run( + `openshell provider create --name dynamo --type openai ` + + `--credential OPENAI_API_KEY=dummy ` + + `--config OPENAI_BASE_URL=${shellQuote(dynamoEndpoint)} 2>&1 || ` + + `openshell provider update dynamo --credential OPENAI_API_KEY=dummy ` + + `--config OPENAI_BASE_URL=${shellQuote(dynamoEndpoint)} 2>&1 || true`, + { ignoreError: true } + ); + run( + `openshell inference set --no-verify --provider dynamo --model ${shellQuote(model)} 2>/dev/null || true`, + { ignoreError: true } + ); + } else if (provider === "nvidia-nim") { // Create nvidia-nim provider run( `openshell provider create --name nvidia-nim --type openai ` + @@ -850,6 +882,7 @@ function printDashboard(sandboxName, model, provider) { if (provider === "nvidia-nim") providerLabel = "NVIDIA Cloud API"; else if (provider === "vllm-local") providerLabel = "Local vLLM"; else if (provider === "ollama-local") providerLabel = "Local Ollama"; + else if (provider === "dynamo") providerLabel = "Dynamo vLLM"; console.log(""); console.log(` ${"─".repeat(50)}`);