fix(onboard): probe host pythons and fall back before Model Router venv setup#3786
Conversation
…nv setup Closes #3781 Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
📝 WalkthroughWalkthroughHost Python discovery and venv bootstrap for Model Router: probes candidate interpreters for required stdlib modules and version bounds, selects healthy candidates (supports strict override), attempts venv creation per-candidate, integrates into onboarding, and documents host requirements and failure messages. ChangesModel Router Python Discovery and Venv Setup
Sequence DiagramsequenceDiagram
participant pickHostPython
participant which
participant probe
participant prepareModelRouterVenv
participant python_m_venv
pickHostPython->>which: resolve candidate names to absolute paths
which-->>pickHostPython: return paths
pickHostPython->>probe: run probe script to import stdlib modules and emit JSON
probe-->>pickHostPython: JSON version or error
pickHostPython->>prepareModelRouterVenv: healthy candidates and failures
prepareModelRouterVenv->>python_m_venv: run python -m venv for each candidate
python_m_venv-->>prepareModelRouterVenv: success or stderr/exit
prepareModelRouterVenv-->>pickHostPython: venv python path or aggregated error
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Comment |
|
🌿 Preview your docs: https://nvidia-preview-pr-3786.docs.buildwithfern.com/nemoclaw |
E2E Advisor RecommendationRequired E2E: Dispatch hint: Full advisor summaryE2E Recommendation AdvisorBase: Required E2E
Optional E2E
New E2E recommendations
Dispatch hint
|
…ck across pythons Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (6)
docs/reference/commands.mdx (1)
1151-1151: ⚡ Quick winReplace colon with period in environment variable description.
The phrase "Strict: NemoClaw probes..." uses a colon to separate clauses rather than introduce a list.
As per coding guidelines, "Colons should only introduce a list. Flag colons used as general punctuation between clauses."
Suggested fix
-| `NEMOCLAW_MODEL_ROUTER_PYTHON` | absolute path | Pins the host Python interpreter used to create the Model Router virtual environment. Strict: NemoClaw probes only that interpreter and aborts with the failure reason if it does not qualify, rather than silently falling back to another python. When unset, NemoClaw probes `python3.13`, `python3.12`, `python3.11`, `python3.10`, and bare `python3`, retains every interpreter whose version is in `[3.10, 3.14)` and whose `ensurepip`, `pyexpat`, `ssl`, and `venv` stdlib modules import cleanly, and tries `python -m venv` on each in priority order until one succeeds. Set the pin when the auto-discovered interpreter is broken (for example, Homebrew `python@3.14` with a `pyexpat` dlopen mismatch on macOS). | +| `NEMOCLAW_MODEL_ROUTER_PYTHON` | absolute path | Pins the host Python interpreter used to create the Model Router virtual environment. Strict. NemoClaw probes only that interpreter and aborts with the failure reason if it does not qualify, rather than silently falling back to another python. When unset, NemoClaw probes `python3.13`, `python3.12`, `python3.11`, `python3.10`, and bare `python3`, retains every interpreter whose version is in `[3.10, 3.14)` and whose `ensurepip`, `pyexpat`, `ssl`, and `venv` stdlib modules import cleanly, and tries `python -m venv` on each in priority order until one succeeds. Set the pin when the auto-discovered interpreter is broken (for example, Homebrew `python@3.14` with a `pyexpat` dlopen mismatch on macOS). |🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/reference/commands.mdx` at line 1151, In the NEMOCLAW_MODEL_ROUTER_PYTHON environment variable description, replace the colon after the word "Strict" with a period and adjust capitalization if needed so the sentence reads as two sentences (e.g., "Strict. NemoClaw probes only...")—update the text near the NEMOCLAW_MODEL_ROUTER_PYTHON entry in docs/reference/commands.mdx to use a period instead of the colon to conform to the colon-usage guideline.docs/reference/commands.md (1)
1164-1164: ⚡ Quick winReplace colon with period in environment variable description.
The phrase "Strict: NemoClaw probes..." uses a colon to separate clauses rather than introduce a list.
As per coding guidelines, "Colons should only introduce a list. Flag colons used as general punctuation between clauses."
Suggested fix
-| `NEMOCLAW_MODEL_ROUTER_PYTHON` | absolute path | Pins the host Python interpreter used to create the Model Router virtual environment. Strict: NemoClaw probes only that interpreter and aborts with the failure reason if it does not qualify, rather than silently falling back to another python. When unset, NemoClaw probes `python3.13`, `python3.12`, `python3.11`, `python3.10`, and bare `python3`, retains every interpreter whose version is in `[3.10, 3.14)` and whose `ensurepip`, `pyexpat`, `ssl`, and `venv` stdlib modules import cleanly, and tries `python -m venv` on each in priority order until one succeeds. Set the pin when the auto-discovered interpreter is broken (for example, Homebrew `python@3.14` with a `pyexpat` dlopen mismatch on macOS). | +| `NEMOCLAW_MODEL_ROUTER_PYTHON` | absolute path | Pins the host Python interpreter used to create the Model Router virtual environment. Strict. NemoClaw probes only that interpreter and aborts with the failure reason if it does not qualify, rather than silently falling back to another python. When unset, NemoClaw probes `python3.13`, `python3.12`, `python3.11`, `python3.10`, and bare `python3`, retains every interpreter whose version is in `[3.10, 3.14)` and whose `ensurepip`, `pyexpat`, `ssl`, and `venv` stdlib modules import cleanly, and tries `python -m venv` on each in priority order until one succeeds. Set the pin when the auto-discovered interpreter is broken (for example, Homebrew `python@3.14` with a `pyexpat` dlopen mismatch on macOS). |🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/reference/commands.md` at line 1164, Update the environment variable description for NEMOCLAW_MODEL_ROUTER_PYTHON by replacing the colon after "Strict" with a period and capitalizing the following clause so it reads "Strict. NemoClaw probes only that interpreter..." (ensure you modify the string that begins with `NEMOCLAW_MODEL_ROUTER_PYTHON` in the docs so punctuation follows the guideline that colons only introduce lists).docs/inference/inference-options.md (1)
122-122: ⚡ Quick winReplace colon with period.
The colon separates two independent clauses rather than introducing a list.
Colons should only introduce lists, per the style guide.As per coding guidelines, "Colons should only introduce a list. Flag colons used as general punctuation between clauses."
Suggested fix
-The pin is strict: NemoClaw probes only that interpreter and aborts with the failure reason if it does not qualify, rather than silently falling back to a different python on `PATH`. +The pin is strict. +NemoClaw probes only that interpreter and aborts with the failure reason if it does not qualify, rather than silently falling back to a different python on `PATH`.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/inference/inference-options.md` at line 122, Change the sentence "The pin is strict: NemoClaw probes only that interpreter and aborts with the failure reason if it does not qualify, rather than silently falling back to a different python on `PATH`." to use a period instead of a colon so it reads "The pin is strict. NemoClaw probes only that interpreter..."—ensure spacing and capitalization are correct after replacing the colon.docs/inference/inference-options.mdx (1)
109-109: ⚡ Quick winReplace colon with period.
The colon separates two independent clauses rather than introducing a list.
Colons should only introduce lists, per the style guide.As per coding guidelines, "Colons should only introduce a list. Flag colons used as general punctuation between clauses."
Suggested fix
-The pin is strict: NemoClaw probes only that interpreter and aborts with the failure reason if it does not qualify, rather than silently falling back to a different python on `PATH`. +The pin is strict. +NemoClaw probes only that interpreter and aborts with the failure reason if it does not qualify, rather than silently falling back to a different python on `PATH`.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/inference/inference-options.mdx` at line 109, Replace the colon in the sentence "The pin is strict: NemoClaw probes only that interpreter and aborts with the failure reason if it does not qualify, rather than silently falling back to a different python on `PATH`." with a period so it becomes two independent sentences (e.g., "The pin is strict. NemoClaw probes..."), ensuring the second sentence still begins with "NemoClaw" and preserves the rest of the wording; update the sentence in the inference options doc where that exact phrase appears.src/lib/onboard/model-router-python.test.ts (2)
24-24: 💤 Low valueConsider using a supported version in the default parameter for clarity.
The default
versionof[3, 14, 5]is above the supported ceiling. When tests like line 92–94 omit the version argument, the probe reports both an import error and a version outside the supported range. For tests specifically validating stdlib probe failures (per the test name "falls back when the top candidate fails the stdlib probe"), it would be clearer to default to a version within[3, 10, 3.14), such as[3, 13, 0].Optional refactor
-function probeImportError(detail: string, version: readonly [number, number, number] = [3, 14, 5]) { +function probeImportError(detail: string, version: readonly [number, number, number] = [3, 13, 0]) { return { exit: 1, stdout: JSON.stringify({ version: [...version], error: detail }), stderr: "", }; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/onboard/model-router-python.test.ts` at line 24, The default version used by probeImportError is outside the supported ceiling, causing tests that omit the version to also trigger a "version outside supported range" failure; change the default parameter in probeImportError(version: readonly [number, number, number] = [3, 13, 0]) to a supported tuple (e.g., [3,13,0]) so tests that expect only the stdlib import error (like the "falls back when the top candidate fails the stdlib probe" test) get a supported Python version by default; update any test expectations that intentionally rely on an out-of-range default to pass an explicit version when necessary.
203-203: 💤 Low valueStatic analysis RegExp warning is a false positive.
The warnings about constructing
RegExpfrom a variable flag potential ReDoS vulnerabilities when the pattern comes from untrusted input. Here,OVERRIDE_ENV_VARis a constant string imported from the module under test, not user input, so there is no security risk.Using the constant maintains synchronization with the actual environment variable name. If you prefer to silence the static analysis warning, you could replace with a string literal
/NEMOCLAW_MODEL_ROUTER_PYTHON/, though this trades static analysis cleanliness for slightly looser coupling to the constant.Also applies to: 220-220
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/onboard/model-router-python.test.ts` at line 203, The RegExp-from-variable warning is a static-analysis false positive because OVERRIDE_ENV_VAR is a module constant, so either keep the current assert.match(message, new RegExp(OVERRIDE_ENV_VAR)) and silence the rule for that line by adding an inline eslint disable (e.g., add a single-line comment like // eslint-disable-next-line security/detect-unsafe-regex) immediately above the assert.match call, or replace the RegExp with a literal string match (e.g., assert.match(message, /NEMOCLAW_MODEL_ROUTER_PYTHON/) ) if you prefer to remove the linter suppression; target the assert.match line referencing OVERRIDE_ENV_VAR in model-router-python.test.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/onboard/model-router-python.ts`:
- Around line 291-294: The venv creation currently uses hostPython.command which
may re-resolve to a different interpreter later; change the run invocation that
creates the virtualenv (the call producing venvResult) to use
hostPython.executable instead of hostPython.command so the venv is created with
the exact probed binary and subsequent diagnostics/reference point to
hostPython.executable; keep the same options (ignoreError, timeout,
opts.venvDir) and update any related log/error messages to reference
hostPython.executable.
- Around line 308-314: The final Error thrown at the end of the Model Router
Python setup currently only includes venvFailures, which loses prior stdlib
probe failures; update the throw (in model-router-python.ts where the Error is
constructed) to include both the probe failures and venvFailures (e.g., include
probeFailures or stdlib probe failure messages before venvFailures in the array
passed to join), so the error message preserves the original broken-host
import/probe details as well as the subsequent -m venv failures.
---
Nitpick comments:
In `@docs/inference/inference-options.md`:
- Line 122: Change the sentence "The pin is strict: NemoClaw probes only that
interpreter and aborts with the failure reason if it does not qualify, rather
than silently falling back to a different python on `PATH`." to use a period
instead of a colon so it reads "The pin is strict. NemoClaw probes only that
interpreter..."—ensure spacing and capitalization are correct after replacing
the colon.
In `@docs/inference/inference-options.mdx`:
- Line 109: Replace the colon in the sentence "The pin is strict: NemoClaw
probes only that interpreter and aborts with the failure reason if it does not
qualify, rather than silently falling back to a different python on `PATH`."
with a period so it becomes two independent sentences (e.g., "The pin is strict.
NemoClaw probes..."), ensuring the second sentence still begins with "NemoClaw"
and preserves the rest of the wording; update the sentence in the inference
options doc where that exact phrase appears.
In `@docs/reference/commands.md`:
- Line 1164: Update the environment variable description for
NEMOCLAW_MODEL_ROUTER_PYTHON by replacing the colon after "Strict" with a period
and capitalizing the following clause so it reads "Strict. NemoClaw probes only
that interpreter..." (ensure you modify the string that begins with
`NEMOCLAW_MODEL_ROUTER_PYTHON` in the docs so punctuation follows the guideline
that colons only introduce lists).
In `@docs/reference/commands.mdx`:
- Line 1151: In the NEMOCLAW_MODEL_ROUTER_PYTHON environment variable
description, replace the colon after the word "Strict" with a period and adjust
capitalization if needed so the sentence reads as two sentences (e.g., "Strict.
NemoClaw probes only...")—update the text near the NEMOCLAW_MODEL_ROUTER_PYTHON
entry in docs/reference/commands.mdx to use a period instead of the colon to
conform to the colon-usage guideline.
In `@src/lib/onboard/model-router-python.test.ts`:
- Line 24: The default version used by probeImportError is outside the supported
ceiling, causing tests that omit the version to also trigger a "version outside
supported range" failure; change the default parameter in
probeImportError(version: readonly [number, number, number] = [3, 13, 0]) to a
supported tuple (e.g., [3,13,0]) so tests that expect only the stdlib import
error (like the "falls back when the top candidate fails the stdlib probe" test)
get a supported Python version by default; update any test expectations that
intentionally rely on an out-of-range default to pass an explicit version when
necessary.
- Line 203: The RegExp-from-variable warning is a static-analysis false positive
because OVERRIDE_ENV_VAR is a module constant, so either keep the current
assert.match(message, new RegExp(OVERRIDE_ENV_VAR)) and silence the rule for
that line by adding an inline eslint disable (e.g., add a single-line comment
like // eslint-disable-next-line security/detect-unsafe-regex) immediately above
the assert.match call, or replace the RegExp with a literal string match (e.g.,
assert.match(message, /NEMOCLAW_MODEL_ROUTER_PYTHON/) ) if you prefer to remove
the linter suppression; target the assert.match line referencing
OVERRIDE_ENV_VAR in model-router-python.test.ts.
🪄 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: 42884b4c-be81-4012-83b9-a145cad8e17e
📒 Files selected for processing (8)
docs/inference/inference-options.mddocs/inference/inference-options.mdxdocs/reference/commands.mddocs/reference/commands.mdxsrc/lib/onboard.tssrc/lib/onboard/model-router-python.test.tssrc/lib/onboard/model-router-python.tstest/onboard-model-router.test.ts
…lures in errors Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
There was a problem hiding this comment.
🧹 Nitpick comments (4)
docs/inference/inference-options.mdx (2)
110-112: ⚡ Quick winUse inline code formatting for CLI command names in prose.
Line 110 and Line 112 use plain-text
pythonin command-context prose; format those command names as inline code for consistency.As per coding guidelines, "CLI commands, file paths, flags, parameter names, and values must use inline
codeformatting."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/inference/inference-options.mdx` around lines 110 - 112, Update the prose to use inline code formatting for the CLI command names mentioned: replace plain-text instances of python, python3.12, command -v python3.12, and python -m venv with inline `code` formatting (e.g., `python`, `python3.12`, `command -v python3.12`, `python -m venv`) so the sentences in the NemoClaw probing paragraph follow the CLI/paths/flags formatting guideline.
111-111: ⚡ Quick winRewrite passive voice to active voice.
Line 111 uses passive voice ("are rejected"). Please switch this to an active construction.
As per coding guidelines, "Active voice required. Flag passive constructions."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/inference/inference-options.mdx` at line 111, Change the passive sentence "Relative command names such as `python3.12` are rejected; use `command -v python3.12` to find the absolute path." to an active construction that names the actor—e.g., start with "The system rejects relative command names such as `python3.12`; use `command -v python3.12` to find the absolute path."—so replace the passive verb "are rejected" with an active verb phrase referencing "the system" while keeping the example text (`python3.12` and `command -v python3.12`) intact.docs/inference/inference-options.md (2)
123-125: ⚡ Quick winUse inline code formatting for CLI command names in prose.
Line 123 and Line 125 use plain-text
pythonin command-context prose; format those command names as inline code for consistency.As per coding guidelines, "CLI commands, file paths, flags, parameter names, and values must use inline
codeformatting."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/inference/inference-options.md` around lines 123 - 125, Update the prose in docs/inference/inference-options.md so CLI command names use inline code formatting: change plain "python" occurrences in the sentence "NemoClaw probes only that interpreter..." and the phrase "If python -m venv itself fails..." to use inline code formatting (e.g., `python`, `python -m venv`); ensure relative command examples like python3.12 are also rendered as code (e.g., `python3.12`) and keep the rest of the wording intact.
124-124: ⚡ Quick winRewrite passive voice to active voice.
Line 124 uses passive voice ("are rejected"). Please switch this to an active construction.
As per coding guidelines, "Active voice required. Flag passive constructions."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/inference/inference-options.md` at line 124, Change the passive sentence "Relative command names such as `python3.12` are rejected; use `command -v python3.12` to find the absolute path." to active voice by making the subject perform the action (for example, "The system rejects relative command names such as `python3.12`; use `command -v python3.12` to find the absolute path."). Update the sentence in the docs/inference/inference-options.md content where the phrase "Relative command names such as `python3.12`" appears so the wording uses active voice (e.g., "The system rejects..." or "We reject...") while keeping the recommendation to use `command -v python3.12`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@docs/inference/inference-options.md`:
- Around line 123-125: Update the prose in docs/inference/inference-options.md
so CLI command names use inline code formatting: change plain "python"
occurrences in the sentence "NemoClaw probes only that interpreter..." and the
phrase "If python -m venv itself fails..." to use inline code formatting (e.g.,
`python`, `python -m venv`); ensure relative command examples like python3.12
are also rendered as code (e.g., `python3.12`) and keep the rest of the wording
intact.
- Line 124: Change the passive sentence "Relative command names such as
`python3.12` are rejected; use `command -v python3.12` to find the absolute
path." to active voice by making the subject perform the action (for example,
"The system rejects relative command names such as `python3.12`; use `command -v
python3.12` to find the absolute path."). Update the sentence in the
docs/inference/inference-options.md content where the phrase "Relative command
names such as `python3.12`" appears so the wording uses active voice (e.g., "The
system rejects..." or "We reject...") while keeping the recommendation to use
`command -v python3.12`.
In `@docs/inference/inference-options.mdx`:
- Around line 110-112: Update the prose to use inline code formatting for the
CLI command names mentioned: replace plain-text instances of python, python3.12,
command -v python3.12, and python -m venv with inline `code` formatting (e.g.,
`python`, `python3.12`, `command -v python3.12`, `python -m venv`) so the
sentences in the NemoClaw probing paragraph follow the CLI/paths/flags
formatting guideline.
- Line 111: Change the passive sentence "Relative command names such as
`python3.12` are rejected; use `command -v python3.12` to find the absolute
path." to an active construction that names the actor—e.g., start with "The
system rejects relative command names such as `python3.12`; use `command -v
python3.12` to find the absolute path."—so replace the passive verb "are
rejected" with an active verb phrase referencing "the system" while keeping the
example text (`python3.12` and `command -v python3.12`) intact.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 185b95df-c043-4362-8890-d74f73cdf23a
📒 Files selected for processing (7)
docs/inference/inference-options.mddocs/inference/inference-options.mdxdocs/reference/commands.mddocs/reference/commands.mdxsrc/lib/onboard.tssrc/lib/onboard/model-router-python.test.tssrc/lib/onboard/model-router-python.ts
✅ Files skipped from review due to trivial changes (1)
- docs/reference/commands.md
🚧 Files skipped from review as they are similar to previous changes (2)
- docs/reference/commands.mdx
- src/lib/onboard.ts
Selective E2E Results — ✅ All requested jobs passedRun: 26116771755
|
cjagwani
left a comment
There was a problem hiding this comment.
LGTM. Acceptance match against #3781 is a perfect 4/4, scope is tight, tests are well-structured (DI, no real spawn), and the two CodeRabbit majors on 95a6a03 are properly resolved in 783bb56 (absolute-path spawn + merged probe+venv-stage error).
Couple of optional nits, none blocking merge:
-
prepareModelRouterVenv's venv-stage fallback (probe-healthy python whose-m venvfails, retry next candidate) is the headline P2 behavior but it's only indirectly covered — the unit test asserts thehealthy[]list shape, not the loop. Worth adding aprepareModelRouterVenvtest where a fake-python's-m venvreturns non-zero for the top candidate and zero for the second. Cheap insurance against a future refactor flattening that loop. -
MAX_PYTHON_EXCLUSIVE = [3, 14]is gated by an explicit test, which is the right call. Tracking suggestion: drop a TODO/issue link pointing at the upstream wheel-coverage signal (torch + litellm cp314) so we don't forget to bump.
The unrelated CI / Pull Request / checks red is a flake in src/lib/inference/local.test.ts:49:3 (5s timeout on a sync URL assertion) — not your code.
ericksoa
left a comment
There was a problem hiding this comment.
Approved after adversarial follow-up fixes and validation. Focused model-router regression and onboard nightly slice are green, and the PR check rerun is clean.
## Summary Refreshes the NemoClaw docs for v0.0.46 by updating version metadata, release notes, and generated user skills. The refresh also keeps public docs aligned with the docs skip list by removing non-public experimental references from the generated output. ## Related Issue None. ## Changes - #3744 and #3824 -> `docs/about/release-notes.mdx`: Added Windows bootstrap and WSL express install coverage for v0.0.46. - #3392 -> `docs/manage-sandboxes/messaging-channels.mdx`, `docs/reference/commands.mdx`, `docs/reference/network-policies.mdx`, and policy examples: Refreshed public messaging channel docs around WhatsApp and matching policy presets. - #3742, #3767, #3732, #3786, #3777, and #3808 -> `docs/about/release-notes.mdx`: Added release-note coverage for Hermes managed tools, Bedrock Runtime endpoint detection, WSL Ollama proxying, Model Router Python fallback, plugin command registration, and tool-catalog latency improvements. - #3124 -> `docs/about/release-notes.mdx`: Added release-note coverage for hosted uninstall flag guidance. - Generated `nemoclaw-user-*` skills from the updated MDX docs for the v0.0.46 release. ## 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 - [ ] `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 - [ ] `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) Verification notes: - Commit hooks passed, including markdownlint, gitleaks, docs-to-skills verification, env-var docs, and skills YAML checks. - `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --doc-platform fern-mdx` passed. - `bash test/e2e/e2e-cloud-experimental/check-docs.sh --only-links --local-only --with-skills` passed. - `git diff --check` passed. - `make docs` was attempted but blocked before MDX validation because `npx` received HTTP 403 fetching `fern-api` from npm. --- Signed-off-by: Miyoung Choi <miyoungc@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Released v0.0.46: improved Windows setup, WhatsApp messaging support, Hermes sandbox/tool routing, Anthropic endpoint compatibility, Ollama proxy routing, model-router fallback, OpenClaw plugin/backup compatibility, sandbox build tooling fixes, and updated uninstall flag behavior. * **Documentation** * Removed WeChat from messaging flows and presets across guides and CLI docs; clarified onboarding and channel setup for WhatsApp. Clarified runtime mutability and filesystem (Landlock) behavior — some changes require sandbox rebuilds; prefer host-side commands for durable config. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/NVIDIA/NemoClaw/pull/3911?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Summary
Model Router venv setup used to grab whatever
python3resolved to first and runpython -m venvunconditionally. When that python's stdlib was broken at the C-extension level (e.g. Homebrewpython@3.14with apyexpatdlopen mismatch against the systemlibexpat), onboarding aborted with a generic "Failed to create Model Router virtual environment." message and made no attempt to fall back to a healthy interpreter — even when one was right there on PATH.Related Issue
Fixes #3781
Changes
pickHostPythonhelper insrc/lib/onboard/model-router-python.tsprobespython3.13,python3.12,python3.11,python3.10, and barepython3(plus an optionalNEMOCLAW_MODEL_ROUTER_PYTHONoverride) and adopts the first interpreter whose version is in[3.10, 3.14)and whoseensurepip,pyexpat,ssl, andvenvstdlib modules import cleanly.installModelRouterCommandnow delegates the host-python probe andpython -m venvinvocation toprepareModelRouterVenv, which surfaces the real per-candidate failure (for example, the_XML_SetAllocTrackerActivationThresholdImportError) when no candidate qualifies.NEMOCLAW_MODEL_ROUTER_PYTHONoverride indocs/inference/inference-options.mdanddocs/reference/commands.md.pickHostPythonunit tests covering version-range bounds, stdlib import failures, candidate dedup, env-var override, and the formatted error path. Updates the existing Model Router integration tests so the fakepython3stub answers the new probe.Type of Change
Verification
npx prek run --all-filespassesnpm testpassesmake docsbuilds without warnings (doc changes only)Signed-off-by: Tinson Lai tinsonl@nvidia.com
Summary by CodeRabbit
New Features
Documentation
Tests