Skip to content

fix(uninstall): stop model router during teardown - #5194

Merged
cv merged 4 commits into
NVIDIA:mainfrom
Thabhelo:fix/uninstall-model-router-5169
Jun 13, 2026
Merged

fix(uninstall): stop model router during teardown#5194
cv merged 4 commits into
NVIDIA:mainfrom
Thabhelo:fix/uninstall-model-router-5169

Conversation

@Thabhelo

@Thabhelo Thabhelo commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Stop the routed onboard model-router process during uninstall so port 4000 is freed before state cleanup and re-onboard does not fail with "Port 4000 already has a healthy router endpoint".

Related Issue

Fixes #5169

Changes

  • Add stop-model-router to the uninstall plan's "Stopping services" step
  • Implement stopModelRouter() mirroring the Ollama auth-proxy path: read routerPid from ~/.nemoclaw/onboard-session.json, verify cmdline, fall back to lsof on :4000
  • Add regression tests for session PID, orphan lsof, foreign-owner, and wrong-cmdline cases

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
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • npm run 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)

Signed-off-by: Thabhelo 50872400+Thabhelo@users.noreply.github.com

Summary by CodeRabbit

  • Bug Fixes

    • Uninstall reliably stops the model-router during cleanup (including orphaned instances bound to the router port) and avoids stopping unrelated or foreign-owned processes.
    • Onboarding recovers from mismatched PID ownership by locating/stopping orphaned model-router instances for the expected port or prompting the user when incompatible routers remain.
  • New Features

    • Uninstall plan now explicitly includes a model-router stop step.
  • Tests

    • Added tests for model-router shutdown, port-based discovery, ownership checks, and command-line matching.

Uninstall left the routed onboard model-router process running on port
4000, blocking re-onboard. Mirror the Ollama auth-proxy stop path using
onboard-session routerPid and an lsof fallback with cmdline verification.

Fixes NVIDIA#5169
@copy-pr-bot

copy-pr-bot Bot commented Jun 11, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 8024d7c8-8c63-47c7-8d99-6d80d69b4f21

📥 Commits

Reviewing files that changed from the base of the PR and between 9bb6b19 and bf2e481.

📒 Files selected for processing (2)
  • src/lib/actions/uninstall/run-plan.test.ts
  • src/lib/domain/uninstall/plan.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/domain/uninstall/plan.test.ts
  • src/lib/actions/uninstall/run-plan.test.ts

📝 Walkthrough

Walkthrough

Adds a new uninstall action to stop model-router processes; implements PID discovery and validation (cmdline and ownership), graceful SIGTERM→SIGKILL termination with lsof-based orphan scanning for port 4000, integrates stopModelRouter into uninstall, and adds tests for stored-PID, orphan, ownership, and cmdline-gating scenarios.

Changes

Model-Router Cleanup on Uninstall

Layer / File(s) Summary
Uninstall plan schema and builder
src/lib/domain/uninstall/plan.ts, src/lib/domain/uninstall/plan.test.ts
UninstallPlanAction union gains { kind: "stop-model-router" }. The uninstall plan emits this action in the "Stopping services" phase; tests updated to expect the new action in flattened steps and the stopping-services actions.
Model-router process discovery and onboarding integration
src/lib/onboard/model-router-process.ts, src/lib/onboard/model-router-process.test.ts, src/lib/onboard/model-router.ts, src/lib/onboard/model-router.test.ts
Exports findModelRouterPidForPort with optional listProcPids injection, updates isModelRouterCommandLineForPort to detect model-router in argv[0] or argv[1], adds unit tests for discovery behavior, and uses the finder in reconcileModelRouter() to stop orphaned routers when a recorded PID doesn't own the port.
Model-router shutdown implementation and execution
src/lib/actions/uninstall/run-plan.ts
Adds stopModelRouter helpers: reads persisted routerPid, validates existence and cmdline for port 4000 via isModelRouterCommandLineForPort, attempts SIGTERM then SIGKILL with disappearance checks, and falls back to lsof-based orphan scanning filtered by ownership and cmdline. Integrated into the uninstall "Stopping services" execution path.
Model-router shutdown test scenarios
src/lib/actions/uninstall/run-plan.test.ts
Adds MODEL_ROUTER_CMDLINE constant and four Vitest cases verifying: stopping by stored routerPid, orphan discovery via lsof, refusal to stop foreign-owned processes, and cmdline-gating to avoid stopping non-matching processes. Tests assert PID killed state and expected log messages.

Sequence Diagram

sequenceDiagram
  participant User
  participant RunUninstallPlan
  participant stopModelRouter
  participant ps_cmd
  participant lsof_cmd
  participant OS
  User->>RunUninstallPlan: run uninstall
  RunUninstallPlan->>stopModelRouter: invoke stopModelRouter(paths,runtime)
  stopModelRouter->>ps_cmd: read cmdline for tracked PID / validate ownership
  ps_cmd-->>stopModelRouter: cmdline + owner info
  stopModelRouter->>OS: send SIGTERM
  OS-->>stopModelRouter: PID alive?
  stopModelRouter->>OS: send SIGKILL (if needed)
  stopModelRouter->>lsof_cmd: lsof -ti :4000 (fallback)
  lsof_cmd-->>stopModelRouter: candidate PIDs
  stopModelRouter->>ps_cmd: verify cmdline + ownership for candidates
  stopModelRouter-->>RunUninstallPlan: log results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

"🐰 I sniffed the port and found a clue,
A router sitting on four-oh-oh-oh-two,
SIGTERM first, then SIGKILL if it stays,
Orphans found and politely chased away.
Uninstall hops on, the system breathes anew."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 'fix(uninstall): stop model router during teardown' clearly summarizes the main change: ensuring the model-router process is stopped as part of the uninstall sequence.
Linked Issues check ✅ Passed The PR fully addresses the objective from issue #5169: it implements logic to detect and stop the model-router process during uninstall, handles both session PID and lsof discovery, validates command-line patterns including Python venv invocations, and adds comprehensive regression tests for session PID, orphan lsof, foreign-owner, and wrong-cmdline scenarios.
Out of Scope Changes check ✅ Passed All changes are within scope: uninstall model-router cleanup, model-router process discovery, command-line validation enhancements, and onboard orphan recovery. The PR explicitly excludes Hermes gateway wait and API_SERVER_KEY injection mentioned in #5230 as out of scope.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Uninstall and onboard both failed to stop routers started via the venv
interpreter (python /path/model-router proxy). Also auto-recover orphaned
routers during reconcileModelRouter when session PID is stale.

Incorporates NVIDIA#5169-relevant pieces from NVIDIA#5230; Hermes gateway changes
left out of scope.
@Thabhelo

Copy link
Copy Markdown
Contributor Author

Updated after @tyeth-ai-assisted's note on #5230:

  • Python venv cmdlineisModelRouterCommandLineForPort now checks args[0] or args[1] (real-world: python /path/model-router proxy …)
  • Onboard orphan recoveryfindModelRouterPidForPort + reconcileModelRouter auto-stop when port 4000 is healthy but session PID is stale
  • Tests use Python-interpreter cmdlines

Left Hermes gateway wait / API_SERVER_KEY injection from #5230 out of scope here — separate concern.

Thanks for the pointer — that cmdline gap would have made the uninstall stop silently no-op in production.

@wscurran wscurran added area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow bug-fix PR fixes a bug or regression labels Jun 12, 2026
@wscurran

Copy link
Copy Markdown
Contributor

✨ Thanks for adding the stop-model-router step to the uninstall plan with regression tests covering session PID, orphan lsof, foreign-owner, and wrong-cmdline cases. This proposes a way to stop the routed onboard model-router process during uninstall so port 4000 is freed before state cleanup.


Related open issues:

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

CI is green on the current head, CodeRabbit has no actionable comments on the latest review, and the PR includes focused regression coverage for the uninstall/model-router cleanup paths. I checked the available live E2E lanes: the nearest model-router E2E is not safely dispatchable against this fork head via a trusted target_ref workflow, so I am not running the secret-bearing regression workflow on the fork ref.

@cv
cv merged commit 4f991f5 into NVIDIA:main Jun 13, 2026
33 of 35 checks passed
@cv cv added the v0.0.65 label Jun 13, 2026
@miyoungc miyoungc mentioned this pull request Jun 16, 2026
13 tasks
cv pushed a commit that referenced this pull request Jun 17, 2026
## Summary
Refreshes release-prep documentation for NemoClaw v0.0.65.
Adds the v0.0.65 release-notes section and refreshes generated
`nemoclaw-user-*` skills from the Fern MDX source docs.

## Changes
- Added the v0.0.65 release notes to `docs/about/release-notes.mdx` with
links to the deeper docs pages for lifecycle, troubleshooting,
inference, CLI commands, messaging, credentials, network policy, Hermes,
and sub-agents.
- Regenerated the `nemoclaw-user-*` skills with
`scripts/docs-to-skills.py` so release-prep skill output matches the
merged source docs.
- Used the v0.0.65 announcement discussion as release context:
#5472.

## Source Summary
- #2492 -> `docs/about/release-notes.mdx`: Documents deadline-based
gateway wait reliability in the v0.0.65 recovery summary.
- #4958 -> `docs/about/release-notes.mdx`: Documents re-execed OpenClaw
gateway health check recovery in the sandbox recovery summary.
- #5163 -> `docs/about/release-notes.mdx`: Documents safer uninstall TTY
confirmation behavior in the day-two CLI summary.
- #5178 -> `docs/about/release-notes.mdx`: Documents fail-closed config
restore merge behavior in the rebuild and restore summary.
- #5179 -> `docs/about/release-notes.mdx`: Documents WeChat QR token
redaction in the messaging summary.
- #5182 -> `docs/about/release-notes.mdx`: Documents sustained gateway
serving checks in the recovery summary.
- #5194 -> `docs/about/release-notes.mdx`: Documents model-router
teardown during uninstall in the day-two CLI summary.
- #5195 -> `docs/about/release-notes.mdx`: Documents Shields
auto-restore lock reconfirmation in the rebuild and restore summary.
- #5198 -> `docs/about/release-notes.mdx`: Documents Docker Desktop WSL
CDI injection failure handling in the onboarding diagnostics summary.
- #5201 -> `docs/about/release-notes.mdx`: Documents sandbox
download/upload wrappers and sessions export in the day-two CLI summary.
- #5205 -> `docs/about/release-notes.mdx`: Documents reporter-owned
model metadata preservation in the rebuild and restore summary.
- #5214 -> `docs/about/release-notes.mdx`: Documents managed vLLM model
preflight before side effects in the inference setup summary.
- #5215 -> `docs/about/release-notes.mdx`: Documents managed vLLM extra
serve arguments in the inference setup summary.
- #5216 -> `docs/about/release-notes.mdx`: Documents silent OpenClaw
runtime fallback surfacing in the onboarding diagnostics summary.
- #5225 -> `docs/about/release-notes.mdx`: Documents persisted sandbox
gateway lookup in the gateway recovery summary.
- #5238 -> `docs/about/release-notes.mdx`: Documents sub-agent gateway
dial-back through the sandbox interface in the Hermes and sub-agent
summary.
- #5248 -> `docs/about/release-notes.mdx`: Documents Discord per-account
proxy resolution in the messaging summary.
- #5264 -> `docs/about/release-notes.mdx`: Documents reserved Hermes
port `8642` handling in the Hermes compatibility summary.
- #5267 -> `docs/about/release-notes.mdx`: Documents the narrower Hermes
baseline policy in the Hermes compatibility summary.
- #5321 -> `docs/about/release-notes.mdx`: Documents restored gateway
guard chains in the gateway recovery summary.
- #5328 -> `docs/about/release-notes.mdx`: Documents compact persisted
messaging plans in the messaging summary.
- #5338 -> `docs/about/release-notes.mdx`: Documents manifest channel
migration in the messaging summary.
- #5352 -> `docs/about/release-notes.mdx`: Documents persisted agent
preservation through registry recovery in the rebuild and restore
summary.
- #5371 ->
`.agents/skills/nemoclaw-user-reference/references/commands.md`:
Refreshes generated skill output for custom build cache and
layer-ordering source docs.
- #5379 -> `docs/about/release-notes.mdx`: Documents dashboard port
allocation across multiple NemoClaw gateways in the recovery summary.
- #5382 -> `docs/about/release-notes.mdx`: Documents recovery when an
active gateway has no sandbox spec in the recovery summary.
- #5389 ->
`.agents/skills/nemoclaw-user-reference/references/troubleshooting.md`:
Refreshes generated skill output for declared agent `forward_ports`
recovery source docs.
- #5400 -> `docs/about/release-notes.mdx`: Documents bounded compatible
endpoint probes in the inference setup summary.
- #5410 -> `docs/about/release-notes.mdx`: Documents provider credential
hash removal from sandbox registry entries in the messaging summary.
- #5418 -> `docs/about/release-notes.mdx`: Documents summarized
inference validation failures in the onboarding diagnostics summary.
- #5457 -> `docs/about/release-notes.mdx`: Documents context-window
recomputation after runtime model switches in the inference setup
summary.
- #5463 -> `docs/about/release-notes.mdx`: Documents cleanup of
hard-coded messaging channel stragglers in the messaging summary.

## Skipped
- #5366 matched `docs/.docs-skip` entries through skipped experimental
paths, so this PR does not add new release-note text for that commit.

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

## Verification
- [x] Git hooks passed during commit and push, or `npx prek run
--from-ref main --to-ref HEAD` passes
- [ ] Targeted tests pass for changed behavior
- [ ] Full `npm test` passes (broad runtime changes only)
- [ ] 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
- [ ] `npm run 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:
- `npm run docs` passed after rerunning outside the sandbox. Fern
reported 0 errors and 1 hidden warning.
- The first sandboxed `npm run docs` attempt failed before validation
because `tsx` could not create its local IPC pipe under sandbox
restrictions.
- `npm run build:cli` passed before push to refresh the local `dist/`
artifacts used by the CLI typecheck hook.
- `npm test` was not run because this is a docs-only release refresh.

---
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 NemoClaw v0.0.65 with improved gateway/sandbox recovery,
safer day-two workflows, and enhanced Hermes compatibility.
* Added managed vLLM extra-arguments configuration via
`NEMOCLAW_VLLM_EXTRA_ARGS_JSON`.
* Added Hermes troubleshooting guidance for port forwarding and health
checks.

* **Documentation**
* Updated NVIDIA Endpoints/NIM setup and examples to use
`NVIDIA_INFERENCE_API_KEY`.
* Refined NVIDIA network policy and Model Router API base configuration.
* Expanded CLI/environment variable documentation (including sub-agent
gateway connectivity) and plugin build performance tips.

* **Tests**
  * Expanded Vitest-backed E2E release validation coverage.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow bug-fix PR fixes a bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

uninstall doesn't remove model-router

3 participants