Skip to content

fix(onboard): decouple local inference providers from OPENAI_API_KEY#2580

Merged
ericksoa merged 9 commits into
mainfrom
fix/local-inference-credential-decoupling
Apr 28, 2026
Merged

fix(onboard): decouple local inference providers from OPENAI_API_KEY#2580
ericksoa merged 9 commits into
mainfrom
fix/local-inference-credential-decoupling

Conversation

@ericksoa

@ericksoa ericksoa commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Local Ollama and local vLLM (incl. NIM) onboards were capturing the host's OPENAI_API_KEY and registering the gateway provider with credentialEnv=OPENAI_API_KEY. A stale or invalid host key would override the local proxy bearer at request time and surface as HTTP 401 on every prompt; an unset key would also block nemoclaw rebuild --auto preflight even though the sandbox never needed an OpenAI key. This PR decouples local inference from the user's OpenAI key entirely.

Related Issue

Refs #2519

Changes

  • Wizard now records credentialEnv = null for ollama-local and vllm-local (both NIM and vllm branches). The "Review configuration" line shows (not required for ...) and onboard-session.json no longer carries OPENAI_API_KEY.
  • setupInference registers the gateway under dedicated internal env names — NEMOCLAW_OLLAMA_PROXY_TOKEN for ollama-local, NEMOCLAW_VLLM_LOCAL_TOKEN for vllm-local — so the gateway never reads the user's host OPENAI_API_KEY.
  • After confirming a local inference provider, any pre-fix OPENAI_API_KEY entry is pruned from ~/.nemoclaw/credentials.json so unset OPENAI_API_KEY; nemoclaw onboard clears the stale value.
  • Rebuild preflight in nemoclaw.ts migrates legacy sandboxes (where onboard-session.json already recorded credentialEnv=OPENAI_API_KEY) by printing a one-time migration notice and proceeding without demanding a host API key.
  • New it.each test in test/rebuild-credential-preflight.test.ts covers the legacy migration for both ollama-local and vllm-local.
  • Existing ollama validation test in test/onboard-selection.test.ts extended to assert credentialEnv === null and that the ollama-local path does not write OPENAI_API_KEY into credentials.json.

Type of Change

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

Verification

  • npx prek run --all-files passes
  • npm test passes for the affected suites (test/rebuild-credential-preflight.test.ts, test/onboard-selection.test.ts) — 41 tests green
  • Tests added for the new behavior (legacy preflight migration; ollama-local credentialEnv=null)
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • make docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Note on npx prek run --all-files: 4 unrelated tests in test/onboard.test.ts (5-second timeout on sandbox-build spawn cases) currently fail on main independent of this PR — verified by running the same isolated case on a clean checkout. Those flakes are out of scope for this fix.

Summary by CodeRabbit

  • Bug Fixes

    • Local inference providers (Ollama, vLLM) no longer rely on your OpenAI API key; they use dedicated local credentials, won’t prompt for or reuse the OpenAI key, and will remove stale OpenAI entries during setup or migration.
    • Rebuild/migration paths detect legacy sessions, show a migration notice, and avoid failing due to obsolete OpenAI credentials.
  • Tests

    • Added tests verifying credential isolation, deletion of stale OpenAI entries, and resilient rebuild/migration behavior.

Local Ollama and local vLLM (incl. NIM) providers were capturing the
host's OPENAI_API_KEY into onboard-session.json and credentials.json,
then registering the gateway provider with credentialEnv=OPENAI_API_KEY.
A stale or invalid host OPENAI_API_KEY would override the local proxy
bearer at request time and surface as HTTP 401 on every prompt; an
unset OPENAI_API_KEY would also block `nemoclaw rebuild --auto`
preflight even though the sandbox never needed an OpenAI key.

The wizard now records credentialEnv=null for ollama-local and
vllm-local. setupInference registers the gateway under dedicated
internal env names (NEMOCLAW_OLLAMA_PROXY_TOKEN /
NEMOCLAW_VLLM_LOCAL_TOKEN) and prunes any pre-fix OPENAI_API_KEY entry
from credentials.json so \`unset OPENAI_API_KEY; nemoclaw onboard\`
behaves as expected.

The rebuild preflight migrates legacy sandboxes that already recorded
credentialEnv=OPENAI_API_KEY by printing a one-time notice and
proceeding without demanding a host API key.

Refs GH #2519

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Local inference providers (Ollama, vLLM) are decoupled from the OpenAI key: new dedicated environment variables are introduced and used; onboarding and rebuild detect and migrate legacy sessions that recorded OPENAI_API_KEY for local providers, and stale OpenAI credentials are removed from disk.

Changes

Cohort / File(s) Summary
Credential env exports
src/lib/onboard-providers.ts
Added exports for local credential envs: OLLAMA_PROXY_CREDENTIAL_ENV (alias) and VLLM_LOCAL_CREDENTIAL_ENV.
Inference config
src/lib/inference-config.ts
Added OLLAMA_LOCAL_CREDENTIAL_ENV = "NEMOCLAW_OLLAMA_PROXY_TOKEN" and VLLM_LOCAL_CREDENTIAL_ENV = "NEMOCLAW_VLLM_LOCAL_TOKEN"; ollama-local and vllm-local use these instead of the default OpenAI env.
Onboarding & setup logic
src/lib/onboard.ts
Local setup treats interactive credentialEnv as null, registers local providers with internal env names/tokens, and removes any existing OPENAI_API_KEY from credentials.json after provider confirmation.
Sandbox rebuild migration
src/nemoclaw.ts
Preflight detects legacy sessions where local providers recorded credentialEnv === "OPENAI_API_KEY", emits a migration notice, and forces rebuildCredentialEnv to null to avoid failing non-interactive rebuilds.
Tests updated/added
src/lib/inference-config.test.ts, test/onboard-selection.test.ts, test/rebuild-credential-preflight.test.ts
Tests updated to expect new dedicated credential envs for local providers; added assertions that ollama-local onboarding does not persist OPENAI_API_KEY and that rebuild preflight migrates legacy sessions without aborting.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI
  participant Onboard as OnboardLogic
  participant Provider as ProviderRegistry
  participant Env as Env (process)
  participant Store as CredentialsStore

  CLI->>Onboard: start setup or rebuild
  Onboard->>Provider: select provider (ollama-local / vllm-local)
  Provider->>Onboard: returns recorded credentialEnv
  alt recorded credentialEnv == "OPENAI_API_KEY" for local provider
    Onboard-->>CLI: log migration notice (GH `#2519`)
    Onboard->>Provider: treat credentialEnv as null
  end
  Onboard->>Env: read dedicated env (OLLAMA_LOCAL_CREDENTIAL_ENV / VLLM_LOCAL_CREDENTIAL_ENV)
  Onboard->>Provider: upsert provider with dedicated credentialEnv / internal token
  Onboard->>Store: delete `OPENAI_API_KEY` if present
  Onboard-->>CLI: continue (setup complete / rebuild proceeds)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nudged the keys and cleaned the trail,

Old OPENAI crumbs no longer prevail.
New tokens nest where local models play,
Ollama and vLLM hop on their way.
Hooray for tidy migration day.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.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 and concisely summarizes the main change: decoupling local inference providers (Ollama, vLLM) from the OPENAI_API_KEY dependency.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/local-inference-credential-decoupling

Comment @coderabbitai help to get the list of available commands and usage tips.

@ericksoa ericksoa self-assigned this Apr 28, 2026

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/onboard.ts`:
- Around line 4752-4754: The call to deleteCredential("OPENAI_API_KEY") is
running too early and must be moved into the successful local-provider setup
path: only invoke deleteCredential after providerResult indicates registration
succeeded and after the local inference setup flow completes (the "inference
set" flow) so we don't remove a user key on failed onboarding; update the
instance where deleteCredential is called near the providerResult check (and the
duplicate at the other occurrence) to run in the success branch that confirms
provider registration and local configuration finished.
- Around line 4741-4751: The sandbox config still serializes legacy credential
envs for local providers; update setupOpenclaw() and
getProviderSelectionConfig(provider, model) so that when provider.id is
"vllm-local" or "ollama-local" (or when using
VLLM_LOCAL_CREDENTIAL_ENV/OLLAMA_LOCAL_CREDENTIAL_ENV), the returned provider
selection object sets credentialEnv (or credential_env) to null/undefined before
writing /sandbox/.nemoclaw/config.json; additionally update
src/lib/inference-config.ts to remove / stop mapping "vllm-local" and
"ollama-local" to OPENAI_API_KEY so consumers of the sandbox config cannot
resurrect the legacy OPENAI_API_KEY requirement.
🪄 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: Enterprise

Run ID: 4ff7ecb8-e9cb-4cc3-b264-199c4bbb8289

📥 Commits

Reviewing files that changed from the base of the PR and between 01d8d9c and 46c3f92.

📒 Files selected for processing (5)
  • src/lib/onboard-providers.ts
  • src/lib/onboard.ts
  • src/nemoclaw.ts
  • test/onboard-selection.test.ts
  • test/rebuild-credential-preflight.test.ts

Comment thread src/lib/onboard.ts
Comment thread src/lib/onboard.ts Outdated
CodeRabbit review on #2580 caught two issues:

1. getProviderSelectionConfig() in inference-config.ts still mapped
   ollama-local and vllm-local to OPENAI_API_KEY. That value flows into
   /sandbox/.nemoclaw/config.json via agent-onboard.ts, so the in-sandbox
   OpenClaw could resurrect the legacy credential requirement even after
   the gateway-side fix.

2. deleteCredential("OPENAI_API_KEY") ran before upsertProvider was
   verified and before `inference set` completed. A failed onboard would
   silently nuke a previously-saved OpenAI key the user may still need
   for a different provider.

Move the credential env definitions to inference-config.ts so the
sandbox-side and gateway-side paths share a single source of truth, and
move both deleteCredential calls to run last in the success path.

Refs GH #2519

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@ericksoa ericksoa added bug Something fails against expected or documented behavior provider: ollama Ollama local model provider behavior labels Apr 28, 2026

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

♻️ Duplicate comments (1)
src/lib/onboard.ts (1)

4756-4771: ⚠️ Potential issue | 🟠 Major

Only prune OPENAI_API_KEY after inference set is actually confirmed.

Line 4756 and Line 4814 ignore the result of runOpenshell(["inference", "set", ...]), so Lines 4767-4771 and 4832-4839 can still delete a valid saved OpenAI key when the apply fails and the route never becomes ready. Move the prune until after the inference set result is checked and verifyInferenceRoute(provider, model) has passed.

Suggested fix
 async function setupInference(
   sandboxName: string | null,
   model: string,
   provider: string,
   endpointUrl: string | null = null,
   credentialEnv: string | null = null,
 ): Promise<{ ok: true; retry?: undefined } | { retry: "selection" }> {
   step(4, 8, "Setting up inference provider");
   runOpenshell(["gateway", "select", GATEWAY_NAME], { ignoreError: true });
+  let shouldPruneLegacyOpenAiKey = false;

   if (
     provider === "nvidia-prod" ||
@@
   } else if (provider === "vllm-local") {
@@
-    runOpenshell([
+    const applyResult = runOpenshell([
       "inference",
       "set",
       "--no-verify",
       "--provider",
       "vllm-local",
@@
       "--timeout",
       String(LOCAL_INFERENCE_TIMEOUT_SECS),
-    ]);
-    // Prune any pre-fix OPENAI_API_KEY entry from credentials.json now that
-    // vllm-local is fully confirmed. Done last so a failed registration
-    // does not delete a credential the user may still need for a remote
-    // provider.
-    deleteCredential("OPENAI_API_KEY");
+    ], { ignoreError: true });
+    if (applyResult.status !== 0) {
+      process.exit(applyResult.status || 1);
+    }
+    shouldPruneLegacyOpenAiKey = true;
   } else if (provider === "ollama-local") {
@@
-    runOpenshell([
+    const applyResult = runOpenshell([
       "inference",
       "set",
       "--no-verify",
       "--provider",
       "ollama-local",
@@
       "--timeout",
       String(LOCAL_INFERENCE_TIMEOUT_SECS),
-    ]);
+    ], { ignoreError: true });
+    if (applyResult.status !== 0) {
+      process.exit(applyResult.status || 1);
+    }
@@
-    deleteCredential("OPENAI_API_KEY");
+    shouldPruneLegacyOpenAiKey = true;
   }

   verifyInferenceRoute(provider, model);
+  if (shouldPruneLegacyOpenAiKey) {
+    deleteCredential("OPENAI_API_KEY");
+  }

Also applies to: 4814-4839

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

In `@src/lib/onboard.ts` around lines 4756 - 4771, The code currently calls
runOpenshell(["inference","set",...]) and then immediately calls
deleteCredential("OPENAI_API_KEY"), which can remove a valid key even if the
inference set fails; change the flow so you capture and check the result of
runOpenshell (the same invocation used at lines around runOpenshell([...])) and
only call deleteCredential("OPENAI_API_KEY") after
verifyInferenceRoute(provider, model) returns success (i.e., the route is
confirmed ready); update the control flow around runOpenshell,
verifyInferenceRoute, and deleteCredential to bail on failure and log/propagate
the error instead of pruning the credential.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/lib/onboard.ts`:
- Around line 4756-4771: The code currently calls
runOpenshell(["inference","set",...]) and then immediately calls
deleteCredential("OPENAI_API_KEY"), which can remove a valid key even if the
inference set fails; change the flow so you capture and check the result of
runOpenshell (the same invocation used at lines around runOpenshell([...])) and
only call deleteCredential("OPENAI_API_KEY") after
verifyInferenceRoute(provider, model) returns success (i.e., the route is
confirmed ready); update the control flow around runOpenshell,
verifyInferenceRoute, and deleteCredential to bail on failure and log/propagate
the error instead of pruning the credential.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 689cbbfe-dbe6-4563-95d4-87e299e00a87

📥 Commits

Reviewing files that changed from the base of the PR and between 46c3f92 and b3f7163.

📒 Files selected for processing (4)
  • src/lib/inference-config.test.ts
  • src/lib/inference-config.ts
  • src/lib/onboard-providers.ts
  • src/lib/onboard.ts

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/onboard.ts`:
- Around line 4803-4807: The code is deleting the global OPENAI_API_KEY from
credentials.json via deleteCredential("OPENAI_API_KEY") during local sandbox
onboarding which mutates shared state; remove the two calls to
deleteCredential("OPENAI_API_KEY") in onboard.ts (the block around the
vllm-local confirmation and the later block referenced) so onboarding no longer
removes the global key, and also remove deleteCredential from the destructured
credentials import (so the symbol is not used); keep all other migration logic
(credentialEnv=null and rebuild preflight) intact.
🪄 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: Enterprise

Run ID: 6bb3d687-606d-4ef9-8328-beb35ee15d68

📥 Commits

Reviewing files that changed from the base of the PR and between b3f7163 and d41df07.

📒 Files selected for processing (1)
  • src/lib/onboard.ts

Comment thread src/lib/onboard.ts Outdated
@cv cv added the v0.0.29 label Apr 28, 2026

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

♻️ Duplicate comments (1)
src/lib/onboard.ts (1)

4998-5002: ⚠️ Potential issue | 🟠 Major

Don't delete the shared OPENAI_API_KEY here.

deleteCredential() updates the global ~/.nemoclaw/credentials.json, not sandbox-scoped state. A successful local-provider onboard can therefore remove the saved key for other OpenAI-backed sandboxes/users on the same host, even though rebuild already migrates legacy local sessions off OPENAI_API_KEY.

Suggested fix
-    // Prune any pre-fix OPENAI_API_KEY entry from credentials.json now that
-    // vllm-local is fully confirmed. Done last so a failed registration
-    // does not delete a credential the user may still need for a remote
-    // provider.
-    deleteCredential("OPENAI_API_KEY");
-    // Prune any pre-fix OPENAI_API_KEY entry from credentials.json now that
-    // ollama-local is fully confirmed (provider registered, inference set,
-    // model warm). Done last so a failed onboard does not delete a credential
-    // the user may still need for a remote provider. Without this, an
-    // invalid OpenAI key cached by an earlier onboard would still be hit by
-    // `getCredential` callers, and `unset OPENAI_API_KEY; nemoclaw onboard`
-    // would not clear it.
-    deleteCredential("OPENAI_API_KEY");

Also applies to: 5063-5070

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

In `@src/lib/onboard.ts` around lines 4998 - 5002, The call to
deleteCredential("OPENAI_API_KEY") is removing the global
~/.nemoclaw/credentials.json entry (affecting other sandboxes/users); remove
that global deletion and instead clear the key only from the sandbox-scoped
state—replace the deleteCredential("OPENAI_API_KEY") invocation with a
sandbox-local update (e.g., call the sandbox credential API used elsewhere in
this module such as updateSandboxCredentials/removeSandboxCredential or mutate
the current sandbox's credentials object and persist it via the existing sandbox
save function) so the global credentials.json is not modified; apply the same
change at the duplicate spot that currently calls deleteCredential for
OPENAI_API_KEY.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/lib/onboard.ts`:
- Around line 4998-5002: The call to deleteCredential("OPENAI_API_KEY") is
removing the global ~/.nemoclaw/credentials.json entry (affecting other
sandboxes/users); remove that global deletion and instead clear the key only
from the sandbox-scoped state—replace the deleteCredential("OPENAI_API_KEY")
invocation with a sandbox-local update (e.g., call the sandbox credential API
used elsewhere in this module such as
updateSandboxCredentials/removeSandboxCredential or mutate the current sandbox's
credentials object and persist it via the existing sandbox save function) so the
global credentials.json is not modified; apply the same change at the duplicate
spot that currently calls deleteCredential for OPENAI_API_KEY.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6aa86b16-d46a-40b5-b192-07c6a4a14c40

📥 Commits

Reviewing files that changed from the base of the PR and between f0b7b1d and a87a785.

📒 Files selected for processing (2)
  • src/lib/onboard.ts
  • src/nemoclaw.ts
✅ Files skipped from review due to trivial changes (1)
  • src/nemoclaw.ts

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

Security review PASS. I checked the local-inference credential path for #2519 and the CodeRabbit major finding: local Ollama/vLLM now register with dedicated internal env names instead of OPENAI_API_KEY, legacy rebuild preflight migrates old local sessions without requiring a host OpenAI key, and the salvage commit preserves any saved OPENAI_API_KEY for unrelated OpenAI-backed sandboxes. Tests cover the selection/session behavior, legacy rebuild migration, and the no-global-delete regression. CI is green; mergeable=MERGEABLE (mergeStateStatus is BLOCKED only because review was required).

@ericksoa ericksoa merged commit a76a65b into main Apr 28, 2026
16 checks passed
@miyoungc miyoungc mentioned this pull request Apr 29, 2026
13 tasks
miyoungc added a commit that referenced this pull request Apr 29, 2026
## Summary
Refreshes the 0.0.29 documentation for user-facing changes merged in the
past 24 hours. Version metadata stays on `0.0.29`.

## Changes
- `docs/get-started/quickstart.md`, `docs/reference/commands.md`, and
`docs/reference/troubleshooting.md`: Document dashboard port
auto-allocation, `--control-ui-port`, and `nemoclaw list` dashboard URL
output from [#2411](#2411).
- `docs/inference/inference-options.md` and
`docs/inference/switch-inference-providers.md`: Document local Ollama
and local vLLM credential isolation from `OPENAI_API_KEY` from
[#2580](#2580).
- `docs/inference/inference-options.md`: Document Local NVIDIA NIM
validation behavior from
[#2505](#2505).
- `docs/reference/commands.md`: Document the cloud-only NIM status
display behavior from
[#2622](#2622).
- `docs/deployment/deploy-to-remote-gpu.md`: Clarify runtime propagation
for `NEMOCLAW_PROXY_HOST` and `NEMOCLAW_PROXY_PORT` from
[#2581](#2581).
- `docs/workspace/backup-restore.md`: Document snapshot restore symlink
handling for sandbox data paths from
[#2488](#2488).
- `docs/reference/commands.md`: Document `skill install --help` and
OpenClaw plugin-shaped directory guidance from
[#2585](#2585).

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

## Verification
- [x] `npx prek run --all-files` passes
- [ ] `npm test` passes
- [ ] Tests added or updated for new or changed behavior
- [x] No secrets, API keys, or credentials committed
- [x] Docs updated for user-facing behavior changes
- [x] `make docs` builds without warnings (doc changes only)
- [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)

## AI Disclosure
- [x] AI-assisted — tool: Codex

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


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

## Summary by CodeRabbit

* **Documentation**
  * Added `--control-ui-port` flag for explicit dashboard port control
* Implemented automatic port selection (18789–18799) when the default
port is occupied
* Clarified that local inference routes (Ollama, local vLLM) don't
require `OPENAI_API_KEY`
  * Improved dashboard URL display in list and status commands
  * Enhanced symlink handling in workspace backup restoration
  * Updated multi-sandbox quickstart and troubleshooting guidance

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@wscurran wscurran added the VDR Linked to VDR finding label Apr 29, 2026
DemianHeyGen pushed a commit to DemianHeyGen/NemoClaw that referenced this pull request Apr 30, 2026
…VIDIA#2580)

## Summary

Local Ollama and local vLLM (incl. NIM) onboards were capturing the
host's `OPENAI_API_KEY` and registering the gateway provider with
`credentialEnv=OPENAI_API_KEY`. A stale or invalid host key would
override the local proxy bearer at request time and surface as HTTP 401
on every prompt; an unset key would also block `nemoclaw rebuild --auto`
preflight even though the sandbox never needed an OpenAI key. This PR
decouples local inference from the user's OpenAI key entirely.

## Related Issue

Refs NVIDIA#2519

## Changes

- Wizard now records `credentialEnv = null` for `ollama-local` and
`vllm-local` (both NIM and vllm branches). The "Review configuration"
line shows `(not required for ...)` and `onboard-session.json` no longer
carries `OPENAI_API_KEY`.
- `setupInference` registers the gateway under dedicated internal env
names — `NEMOCLAW_OLLAMA_PROXY_TOKEN` for ollama-local,
`NEMOCLAW_VLLM_LOCAL_TOKEN` for vllm-local — so the gateway never reads
the user's host `OPENAI_API_KEY`.
- After confirming a local inference provider, any pre-fix
`OPENAI_API_KEY` entry is pruned from `~/.nemoclaw/credentials.json` so
`unset OPENAI_API_KEY; nemoclaw onboard` clears the stale value.
- Rebuild preflight in `nemoclaw.ts` migrates legacy sandboxes (where
`onboard-session.json` already recorded `credentialEnv=OPENAI_API_KEY`)
by printing a one-time migration notice and proceeding without demanding
a host API key.
- New `it.each` test in `test/rebuild-credential-preflight.test.ts`
covers the legacy migration for both `ollama-local` and `vllm-local`.
- Existing ollama validation test in `test/onboard-selection.test.ts`
extended to assert `credentialEnv === null` and that the ollama-local
path does not write `OPENAI_API_KEY` into `credentials.json`.

## Type of Change

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

## Verification

- [ ] `npx prek run --all-files` passes
- [x] `npm test` passes for the affected suites
(`test/rebuild-credential-preflight.test.ts`,
`test/onboard-selection.test.ts`) — 41 tests green
- [x] Tests added for the new behavior (legacy preflight migration;
ollama-local credentialEnv=null)
- [x] No secrets, API keys, or credentials committed
- [ ] Docs updated for user-facing behavior changes
- [ ] `make docs` builds without warnings (doc changes only)
- [ ] 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)

Note on `npx prek run --all-files`: 4 unrelated tests in
`test/onboard.test.ts` (5-second timeout on sandbox-build spawn cases)
currently fail on `main` independent of this PR — verified by running
the same isolated case on a clean checkout. Those flakes are out of
scope for this fix.

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

* **Bug Fixes**
* Local inference providers (Ollama, vLLM) no longer rely on your OpenAI
API key; they use dedicated local credentials, won’t prompt for or reuse
the OpenAI key, and will remove stale OpenAI entries during setup or
migration.
* Rebuild/migration paths detect legacy sessions, show a migration
notice, and avoid failing due to obsolete OpenAI credentials.

* **Tests**
* Added tests verifying credential isolation, deletion of stale OpenAI
entries, and resilient rebuild/migration behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
DemianHeyGen pushed a commit to DemianHeyGen/NemoClaw that referenced this pull request Apr 30, 2026
## Summary
Refreshes the 0.0.29 documentation for user-facing changes merged in the
past 24 hours. Version metadata stays on `0.0.29`.

## Changes
- `docs/get-started/quickstart.md`, `docs/reference/commands.md`, and
`docs/reference/troubleshooting.md`: Document dashboard port
auto-allocation, `--control-ui-port`, and `nemoclaw list` dashboard URL
output from [NVIDIA#2411](NVIDIA#2411).
- `docs/inference/inference-options.md` and
`docs/inference/switch-inference-providers.md`: Document local Ollama
and local vLLM credential isolation from `OPENAI_API_KEY` from
[NVIDIA#2580](NVIDIA#2580).
- `docs/inference/inference-options.md`: Document Local NVIDIA NIM
validation behavior from
[NVIDIA#2505](NVIDIA#2505).
- `docs/reference/commands.md`: Document the cloud-only NIM status
display behavior from
[NVIDIA#2622](NVIDIA#2622).
- `docs/deployment/deploy-to-remote-gpu.md`: Clarify runtime propagation
for `NEMOCLAW_PROXY_HOST` and `NEMOCLAW_PROXY_PORT` from
[NVIDIA#2581](NVIDIA#2581).
- `docs/workspace/backup-restore.md`: Document snapshot restore symlink
handling for sandbox data paths from
[NVIDIA#2488](NVIDIA#2488).
- `docs/reference/commands.md`: Document `skill install --help` and
OpenClaw plugin-shaped directory guidance from
[NVIDIA#2585](NVIDIA#2585).

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

## Verification
- [x] `npx prek run --all-files` passes
- [ ] `npm test` passes
- [ ] Tests added or updated for new or changed behavior
- [x] No secrets, API keys, or credentials committed
- [x] Docs updated for user-facing behavior changes
- [x] `make docs` builds without warnings (doc changes only)
- [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)

## AI Disclosure
- [x] AI-assisted — tool: Codex

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


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

## Summary by CodeRabbit

* **Documentation**
  * Added `--control-ui-port` flag for explicit dashboard port control
* Implemented automatic port selection (18789–18799) when the default
port is occupied
* Clarified that local inference routes (Ollama, local vLLM) don't
require `OPENAI_API_KEY`
  * Improved dashboard URL display in list and status commands
  * Enhanced symlink handling in workspace backup restoration
  * Updated multi-sandbox quickstart and troubleshooting guidance

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@wscurran wscurran added bug-fix PR fixes a bug or regression and removed bug Something fails against expected or documented behavior labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix PR fixes a bug or regression provider: ollama Ollama local model provider behavior VDR Linked to VDR finding

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants