Skip to content
Open
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
7 changes: 7 additions & 0 deletions desktop/docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,13 @@ Personal AI Router and the Go services share one current per-user root:

- `Nvidia Corporation/Personal AI Router`.

Managed engine payloads normally live under that root. vLLM is the deliberate
exception: its load-time GPU build tools cannot parse spaces in source/include
paths, so PAIR installs its private environment at
`~/.nvpair/engine-bin/vllm`. The append-only wipe inventory and every platform
uninstaller include that exact PAIR-owned path; model weights remain in the
separate Hugging Face cache.

On first launch after the rename, Electron data under
`NVIDIA Corporation/PAIR` is merged into the shared directory without
overwriting backend files already present there.
Expand Down
7 changes: 5 additions & 2 deletions desktop/docs/services-parity.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,11 @@ rather than driver-aware or offline-repacked.

The bundled `vllm` manifest covers Linux (NVIDIA GPU) and Apple Silicon macOS
(vLLM-Metal). It installs a pinned vLLM release into a private virtualenv
through a checksum-pinned `uv` bootstrap, or adopts a `vllm` already installed
at a detected path, then runs `vllm serve` on `8001` behind the proxy facade on
at the space-free managed path `~/.nvpair/engine-bin/vllm` through a
checksum-pinned `uv` bootstrap, or adopts a `vllm` already installed at a
detected path. The space-free physical path lets FlashInfer and DeepGEMM compile
load-time GPU kernels; reset and uninstall include the path while preserving the
model cache. It runs `vllm serve` on `8001` behind the proxy facade on
`8000`. vLLM serves one model per process and has no load or unload API, so
Eject (`unload_model`, a `stop_engine` action) stops the engine to free the GPU
and Load on a stopped engine starts it; its model list
Expand Down
14 changes: 12 additions & 2 deletions desktop/scripts/build/installer.nsh
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
; model store as models_dir, and a test in services/nvpair-engine-manager fails
; if one of them resolves inside the app data root.
;
; UNINSTALLER SAFETY: only ever delete the three per-user AppData roots below.
; UNINSTALLER SAFETY: only ever delete the three per-user AppData roots and the
; exact PAIR-managed vLLM payload below.
; Never touch $INSTDIR (C:\Program Files\...). The uninstaller itself lives at
; $INSTDIR\Uninstall ${PRODUCT_FILENAME}.exe and is removed by the template's
; own RMDir /r $INSTDIR + DeleteRegKey; deleting it here would orphan the
Expand All @@ -66,6 +67,7 @@
; - Shared app data: %LOCALAPPDATA%\Nvidia Corporation\Personal AI Router
; - Previous app data: %LOCALAPPDATA%\NVIDIA Corporation\PAIR
; - electron-updater: %LOCALAPPDATA%\nvpair-updater
; - Managed vLLM: %USERPROFILE%\.nvpair\engine-bin\vllm
; On Windows the "NVIDIA Corporation" / "Nvidia Corporation" casing resolves to
; the same case-insensitive folder.
; Per-user data roots. Keep in sync with src/shared/constants/app.ts and the
Expand All @@ -74,10 +76,14 @@
DetailPrint "Removing NVIDIA PAIR user data..."
ClearErrors
ReadEnvStr $0 LOCALAPPDATA
ReadEnvStr $1 USERPROFILE
RMDir /r "$0\Nvidia Corporation\Personal AI Router"
RMDir /r "$0\NVIDIA Corporation\PAIR"
RMDir "$0\NVIDIA Corporation"
RMDir /r "$0\nvpair-updater"
RMDir /r "$1\.nvpair\engine-bin\vllm"
RMDir "$1\.nvpair\engine-bin"
RMDir "$1\.nvpair"
ClearErrors
!macroend

Expand Down Expand Up @@ -109,6 +115,7 @@
; Best-effort: when the user opts to remove data, stop any process whose
; executable lives UNDER one of the data roots (e.g. an engine like Ollama
; running from %LOCALAPPDATA%\Nvidia Corporation\Personal AI Router\engine-bin\)
; or the PAIR-managed vLLM directory
; so RMDir /r can then delete it. Scoped by ExecutablePath, so an external
; Ollama installed elsewhere is never touched. nsExec::ExecToLog never aborts the (un)installer,
; PowerShell swallows its own errors (-ErrorAction SilentlyContinue), and a
Expand All @@ -117,7 +124,7 @@
; containing spaces need no extra quoting.
!macro pairKillProcessesInDataDirs
DetailPrint "Stopping any processes running from NVIDIA PAIR data folders..."
nsExec::ExecToLog 'powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "Get-CimInstance Win32_Process | Where-Object { $$_.ExecutablePath -and ($$_.ExecutablePath -like \"$$env:LOCALAPPDATA\NVIDIA Corporation\PAIR\*\" -or $$_.ExecutablePath -like \"$$env:LOCALAPPDATA\Nvidia Corporation\Personal AI Router\*\") } | ForEach-Object { Stop-Process -Id $$_.ProcessId -Force -ErrorAction SilentlyContinue }"'
nsExec::ExecToLog 'powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "Get-CimInstance Win32_Process | Where-Object { $$_.ExecutablePath -and ($$_.ExecutablePath -like \"$$env:LOCALAPPDATA\NVIDIA Corporation\PAIR\*\" -or $$_.ExecutablePath -like \"$$env:LOCALAPPDATA\Nvidia Corporation\Personal AI Router\*\" -or $$_.ExecutablePath -like \"$$env:USERPROFILE\.nvpair\engine-bin\vllm\*\") } | ForEach-Object { Stop-Process -Id $$_.ProcessId -Force -ErrorAction SilentlyContinue }"'
; Give the OS a moment to release the file handles before RMDir /r.
Sleep 1000
!macroend
Expand All @@ -128,13 +135,16 @@
; continue — the uninstall must never abort over locked user data.
!macro pairWarnIfDataRemains
ReadEnvStr $0 LOCALAPPDATA
ReadEnvStr $1 USERPROFILE
StrCpy $9 ""
IfFileExists "$0\Nvidia Corporation\Personal AI Router\*.*" 0 +2
StrCpy $9 "$9$\n$0\Nvidia Corporation\Personal AI Router"
IfFileExists "$0\NVIDIA Corporation\PAIR\*.*" 0 +2
StrCpy $9 "$9$\n$0\NVIDIA Corporation\PAIR"
IfFileExists "$0\nvpair-updater\*.*" 0 +2
StrCpy $9 "$9$\n$0\nvpair-updater"
IfFileExists "$1\.nvpair\engine-bin\vllm\*.*" 0 +2
StrCpy $9 "$9$\n$1\.nvpair\engine-bin\vllm"
StrCmp $9 "" pairNoLeftover
MessageBox MB_OK|MB_ICONEXCLAMATION "Some NVIDIA PAIR data could not be removed because files were still in use (for example, a running engine such as Ollama).$\n$\nClose those programs, then delete these folders manually:$9"
pairNoLeftover:
Expand Down
6 changes: 5 additions & 1 deletion desktop/scripts/build/linux/after-remove.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ fi

# 4. Remove per-user data only on `purge`, never on a plain `remove`. Per-user
# data here means settings, logs, cluster identity and certificates, and the
# engines NVIDIA PAIR installed under those roots (Ollama and llama.cpp);
# engines NVIDIA PAIR installed under those roots (Ollama and llama.cpp) or in
# its managed space-free vLLM directory;
# downloaded model weights live outside them (~/.ollama, ~/.llamacpp,
# ~/.lmstudio/models) and are never touched.
#
Expand Down Expand Up @@ -81,10 +82,13 @@ case "${1:-}" in
# Every delete is best-effort so a locked or missing path never aborts removal.
rm -rf "$user_home/.config/Nvidia Corporation/Personal AI Router" 2>/dev/null || true
rm -rf "$user_home/.config/NVIDIA Corporation/PAIR" 2>/dev/null || true
rm -rf "$user_home/.nvpair/engine-bin/vllm" 2>/dev/null || true
# Remove the current and previous parents only when empty so other NVIDIA
# applications survive.
rmdir "$user_home/.config/Nvidia Corporation" 2>/dev/null || true
rmdir "$user_home/.config/NVIDIA Corporation" 2>/dev/null || true
rmdir "$user_home/.nvpair/engine-bin" 2>/dev/null || true
rmdir "$user_home/.nvpair" 2>/dev/null || true
fi
;;
esac
Expand Down
3 changes: 3 additions & 0 deletions desktop/scripts/build/macos/uninstall.sh
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,13 @@ echo "Removing user data..."
# scripts/wipe-app-data.sh — do not silently diverge.
rm -rf "$APP_SUPPORT/Nvidia Corporation/Personal AI Router" 2>/dev/null || true
rm -rf "$APP_SUPPORT/NVIDIA Corporation/PAIR" 2>/dev/null || true
rm -rf "$target_home/.nvpair/engine-bin/vllm" 2>/dev/null || true
# Remove the current and previous parents only when empty so other NVIDIA
# applications survive.
rmdir "$APP_SUPPORT/Nvidia Corporation" 2>/dev/null || true
rmdir "$APP_SUPPORT/NVIDIA Corporation" 2>/dev/null || true
rmdir "$target_home/.nvpair/engine-bin" 2>/dev/null || true
rmdir "$target_home/.nvpair" 2>/dev/null || true

# Best-effort removal of macOS framework state keyed on the bundle id.
rm -rf "$target_home/Library/Preferences/$PACKAGE_ID.plist" 2>/dev/null || true
Expand Down
13 changes: 13 additions & 0 deletions desktop/tests/modular/app-data-wipe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ describe('repo-root wipe scripts', () => {
}
})

it('lists the managed space-free vLLM directory in both inventories', () => {
const shText = fs.readFileSync(sh, 'utf8')
const psText = fs.readFileSync(ps1, 'utf8')
expect(shText).toContain('VLLM_INSTALL_ROOT="$HOME_DIR/.nvpair/engine-bin/vllm"')
expect(shText).toContain('TARGETS+=("$VLLM_INSTALL_ROOT|PAIR-managed vLLM payload")')
expect(psText).toContain(
"$VLLMInstallRoot = Join-Path $HomeDir (Join-Path '.nvpair' (Join-Path 'engine-bin' 'vllm'))"
)
expect(psText).toContain(
"@{ Path = $VLLMInstallRoot; Reason = 'PAIR-managed vLLM payload' }"
)
})

it('accepts the app-invoked wait-pid and relaunch options in both twins', () => {
const shText = fs.readFileSync(sh, 'utf8')
const psText = fs.readFileSync(ps1, 'utf8')
Expand Down
5 changes: 3 additions & 2 deletions docs/building.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,9 @@ application running:

On Windows use `scripts\wipe-app-data.cmd` with the same flags. Neither script
needs Node, and both exclude engine model libraries such as `~/.ollama`,
`~/.lmstudio/models`, and `~/.llamacpp` by design, so a reset does not cost you
re-downloading models.
`~/.lmstudio/models`, `~/.llamacpp`, and `~/.cache/huggingface` by design, so a
reset does not cost you re-downloading models. They do remove PAIR's managed
space-free vLLM environment at `~/.nvpair/engine-bin/vllm`.
Start with `--dry-run`. It prints the exact paths and deletes nothing.

If the machine belongs to a cluster, leave the cluster as well, or the other
Expand Down
6 changes: 5 additions & 1 deletion docs/engine-lifecycle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ When you install an engine, consider the following:
and Qwen3.6, so on a Mac they are left out of **Add model**, and loading or
downloading one is refused with a message to choose the BF16 version. Linux,
DGX Spark included, runs them.
Nothing is compiled. vLLM serves a single model per process. Until you choose
PAIR installs its private environment at `~/.nvpair/engine-bin/vllm` so spaces
in the app-data path do not break load-time GPU builds. Reset and uninstall
remove that managed environment while preserving downloaded models.
Installation uses prebuilt wheels; loading a model may compile FlashInfer or
DeepGEMM kernels. vLLM serves a single model per process. Until you choose
one it serves Qwen3.5-4B, downloaded on the first start (about 9.3 GB, and a GPU
with at least 16 GB of memory); on a smaller GPU, add and load a smaller model
first. Its model list
Expand Down
39 changes: 30 additions & 9 deletions scripts/wipe-app-data.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@
# - scripts/wipe-app-data.sh (Unix twin — update both in the same change)
#
# Explicit exclusions (never add): %USERPROFILE%\.ollama, %USERPROFILE%\.llamacpp,
# %USERPROFILE%\.lmstudio, external engine installs, and the application install
# tree (Program Files\PAIR). Those three are the engines' model stores; each
# engine declares its own as models_dir, and nothing PAIR removes may delete one.
# %USERPROFILE%\.lmstudio, %USERPROFILE%\.cache\huggingface, engine installs PAIR
# did not create, and the application install tree (Program Files\PAIR). Those
# home directories are model stores; each engine declares its own as models_dir,
# and nothing PAIR removes may delete one. PAIR's managed vLLM payload is included.
# ---------------------------------------------------------------------------

[CmdletBinding()]
Expand All @@ -51,9 +52,10 @@ Usage: scripts\wipe-app-data.cmd [options]
scripts\wipe-app-data.ps1 [options]

Delete all NVIDIA PAIR-owned application data (settings, logs, cluster
identity, chat history, PAIR-managed engines under the app data root).
identity, chat history, and PAIR-managed engines).

Does NOT delete model libraries (%USERPROFILE%\.ollama, .llamacpp, .lmstudio\models).
Does NOT delete model libraries (%USERPROFILE%\.ollama, .llamacpp,
.lmstudio\models, .cache\huggingface).
Does NOT uninstall the application binary.

Options:
Expand Down Expand Up @@ -106,9 +108,14 @@ if (-not $LocalAppData) {

$HomeDir = $env:USERPROFILE
if (-not $HomeDir) { $HomeDir = $HOME }
if (-not $HomeDir) {
Write-Error 'USERPROFILE is unset'
exit 1
}

$CurrentRoot = Join-Path $LocalAppData (Join-Path $AppOrg $AppDataDirName)
$LegacyRoot = Join-Path $LocalAppData (Join-Path $PreviousOrg $PreviousDataDirName)
$VLLMInstallRoot = Join-Path $HomeDir (Join-Path '.nvpair' (Join-Path 'engine-bin' 'vllm'))

$Username = $env:USERNAME
if (-not $Username) { $Username = 'user' }
Expand All @@ -128,6 +135,7 @@ $ControlDir = Join-Path $Tmp "nvpair-$Scope"
$Targets = @(
@{ Path = $CurrentRoot; Reason = 'Current shared Electron + backend app data root' },
@{ Path = $LegacyRoot; Reason = 'Legacy pre-rename app data root (NVIDIA Corporation/PAIR)' },
@{ Path = $VLLMInstallRoot; Reason = 'PAIR-managed vLLM payload' },
@{ Path = (Join-Path $LocalAppData 'nvpair-updater'); Reason = 'electron-updater download cache (Windows)' },
@{ Path = (Join-Path $CurrentRoot (Join-Path 'bin' 'nvpair.cmd')); Reason = 'Generated Windows nvpair launcher under userData' },
@{ Path = $ControlDir; Reason = 'Removed CLI control token directory' }
Expand Down Expand Up @@ -204,9 +212,10 @@ if ($running.Count -gt 0 -and $ForceKill) {
Write-Host 'Stopping PAIR processes (--force-kill)...'
$killScript = @'
Get-CimInstance Win32_Process | Where-Object {
$_.ExecutablePath -and (
$_.ExecutablePath -like "$env:LOCALAPPDATA\NVIDIA Corporation\PAIR\*" -or
$_.ExecutablePath -like "$env:LOCALAPPDATA\Nvidia Corporation\Personal AI Router\*"
$_.ExecutablePath -and (
$_.ExecutablePath -like "$env:LOCALAPPDATA\NVIDIA Corporation\PAIR\*" -or
$_.ExecutablePath -like "$env:LOCALAPPDATA\Nvidia Corporation\Personal AI Router\*" -or
$_.ExecutablePath -like "$env:USERPROFILE\.nvpair\engine-bin\vllm\*"
)
} | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
'@
Expand All @@ -227,7 +236,7 @@ if (-not $Confirmed) {
}
Write-Host ''
Write-Host 'WARNING: This permanently deletes all NVIDIA PAIR app data.'
Write-Host 'Model libraries (%USERPROFILE%\.ollama, .llamacpp, .lmstudio\models) are NOT removed.'
Write-Host 'Model libraries (%USERPROFILE%\.ollama, .llamacpp, .lmstudio\models, .cache\huggingface) are NOT removed.'
Write-Host ''
Write-Host 'Paths to remove:'
foreach ($t in $Targets) { Write-Host (" - {0}" -f $t.Path) }
Expand Down Expand Up @@ -266,6 +275,18 @@ foreach ($org in @($AppOrg, $PreviousOrg)) {
}
}

foreach ($parent in @(
(Join-Path $HomeDir (Join-Path '.nvpair' 'engine-bin'))
(Join-Path $HomeDir '.nvpair')
)) {
if (Test-Path -LiteralPath $parent) {
$kids = @(Get-ChildItem -LiteralPath $parent -Force -ErrorAction SilentlyContinue)
if ($kids.Count -eq 0) {
try { Remove-Item -LiteralPath $parent -Force -ErrorAction SilentlyContinue } catch { }
}
}
}

Write-Host ("Removed {0} path(s)." -f $removed)
if ($failures -gt 0) {
Write-Error ("{0} path(s) could not be removed." -f $failures)
Expand Down
20 changes: 13 additions & 7 deletions scripts/wipe-app-data.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@
# - desktop/scripts/build/{installer.nsh,linux/after-remove.sh,macos/uninstall.sh}
# - scripts/wipe-app-data.ps1 (Windows twin — update both in the same change)
#
# Explicit exclusions (never add): ~/.ollama, ~/.llamacpp, ~/.lmstudio, external
# engine installs, and the application install tree (Program Files / /opt/PAIR /
# the macOS app bundle). Those three are the engines' model stores; each engine
# declares its own as models_dir, and nothing PAIR removes may delete one.
# Explicit exclusions (never add): ~/.ollama, ~/.llamacpp, ~/.lmstudio,
# ~/.cache/huggingface, engine installs PAIR did not create, and the application
# install tree (Program Files / /opt/PAIR / the macOS app bundle). Those home
# directories are model stores; each engine declares its own as models_dir, and
# nothing PAIR removes may delete one. PAIR's managed vLLM payload is included.
# ---------------------------------------------------------------------------
set -uo pipefail

Expand All @@ -44,9 +45,10 @@ usage() {
Usage: scripts/wipe-app-data.sh [options]

Delete all NVIDIA PAIR-owned application data (settings, logs, cluster
identity, chat history, PAIR-managed engines under the app data root).
identity, chat history, and PAIR-managed engines).

Does NOT delete model libraries (~/.ollama, ~/.llamacpp, ~/.lmstudio/models).
Does NOT delete model libraries (~/.ollama, ~/.llamacpp, ~/.lmstudio/models,
~/.cache/huggingface).
Does NOT uninstall the application binary.

Options:
Expand Down Expand Up @@ -113,6 +115,7 @@ fi

CURRENT_ROOT="$CONFIG_BASE/$APP_ORG/$APP_DATA_DIR_NAME"
LEGACY_ROOT="$CONFIG_BASE/$APP_PREVIOUS_ORG/$APP_PREVIOUS_DATA_DIR_NAME"
VLLM_INSTALL_ROOT="$HOME_DIR/.nvpair/engine-bin/vllm"

USERNAME="${USER:-user}"
if command -v sha256sum >/dev/null 2>&1; then
Expand All @@ -130,6 +133,7 @@ CONTROL_DIR="$RUNTIME_BASE/nvpair-$SCOPE"
TARGETS=()
TARGETS+=("$CURRENT_ROOT|Current shared Electron + backend app data root")
TARGETS+=("$LEGACY_ROOT|Legacy pre-rename app data root (NVIDIA Corporation/PAIR)")
TARGETS+=("$VLLM_INSTALL_ROOT|PAIR-managed vLLM payload")
TARGETS+=("$CACHE_HOME/nvpair-updater|electron-updater download cache")
TARGETS+=("$CONTROL_DIR|Removed CLI control socket directory and auth token")
TARGETS+=("$HOME_DIR/.local/bin/nvpair|Generated Linux nvpair launcher")
Expand Down Expand Up @@ -216,7 +220,7 @@ if [[ "$CONFIRM" -eq 0 ]]; then
fi
echo ""
echo "WARNING: This permanently deletes all NVIDIA PAIR app data."
echo "Model libraries (~/.ollama, ~/.llamacpp, ~/.lmstudio/models) are NOT removed."
echo "Model libraries (~/.ollama, ~/.llamacpp, ~/.lmstudio/models, ~/.cache/huggingface) are NOT removed."
echo ""
echo "Paths to remove:"
for entry in "${TARGETS[@]}"; do
Expand Down Expand Up @@ -251,6 +255,8 @@ done
# Remove org parents only when empty (other NVIDIA apps may share them).
rmdir "$CONFIG_BASE/$APP_ORG" 2>/dev/null || true
rmdir "$CONFIG_BASE/$APP_PREVIOUS_ORG" 2>/dev/null || true
rmdir "$HOME_DIR/.nvpair/engine-bin" 2>/dev/null || true
rmdir "$HOME_DIR/.nvpair" 2>/dev/null || true

echo "Removed $removed path(s)."
if [[ "$failures" -gt 0 ]]; then
Expand Down
Loading
Loading