diff --git a/scripts/install.ps1 b/scripts/install.ps1 index b93df59cb0f..691f7b912a4 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -139,6 +139,11 @@ foreach ($tmpVar in @('TEMP', 'TMP')) { $RepoUrlSsh = "git@github.com:NousResearch/hermes-agent.git" $RepoUrlHttps = "https://github.com/NousResearch/hermes-agent.git" $PythonVersion = "3.11" +# Minor versions the installer accepts when the requested $PythonVersion isn't +# available, in preference order. uv discovers both uv-managed and system +# interpreters, so this list also matches a pre-existing system Python. Single +# source of truth shared by Test-Python's fallback and Resolve-AvailablePythonVersion. +$PythonFallbackVersions = @("3.12", "3.13", "3.10") $NodeVersion = "22" # Stage-protocol version. Bumped only for genuinely breaking changes to the @@ -510,6 +515,31 @@ function Resolve-UvCmd { throw "uv is not installed. Run install.ps1 -Stage uv first." } +function Resolve-AvailablePythonVersion { + # Return the first Python minor version uv can actually find, preferring the + # requested $PythonVersion and then $PythonFallbackVersions. Returns $null + # when none are available. + # + # This is the cross-process-safe counterpart to Test-Python's in-memory + # ``$script:PythonVersion = $fallbackVer`` mutation. Under Hermes-Setup.exe + # each ``-Stage NAME`` runs in a *fresh* powershell.exe, so the fallback the + # ``python`` stage settled on (e.g. 3.12 when 3.11 is absent) does NOT + # survive into the ``venv`` stage's process -- there $PythonVersion is back + # at its "3.11" default. Consumers re-resolve here instead of trusting that + # default, which is exactly the propagation gap behind issue #50769. + $candidates = @($PythonVersion) + $PythonFallbackVersions + $seen = @{} + foreach ($ver in $candidates) { + if (-not $ver -or $seen.ContainsKey($ver)) { continue } + $seen[$ver] = $true + try { + $found = & $UvCmd python find $ver 2>$null + if ($found) { return $ver } + } catch { } + } + return $null +} + function Test-Python { Write-Info "Checking Python $PythonVersion..." @@ -566,7 +596,7 @@ function Test-Python { # Fallback: check if ANY Python 3.10+ is already available on the system Write-Info "Trying to find any existing Python 3.10+..." - foreach ($fallbackVer in @("3.12", "3.13", "3.10")) { + foreach ($fallbackVer in $PythonFallbackVersions) { try { $pythonPath = & $UvCmd python find $fallbackVer 2>$null if ($pythonPath) { @@ -1513,7 +1543,19 @@ function Install-Venv { Write-Info "Skipping virtual environment (-NoVenv)" return } - + + # Re-resolve the interpreter before creating the venv. Under Hermes-Setup.exe + # each stage runs in its own powershell.exe, so the fallback the `python` + # stage picked (e.g. 3.12 when 3.11 is absent) did NOT propagate into this + # fresh process -- $PythonVersion is back at its "3.11" default. Trusting it + # here made `uv venv venv --python 3.11` fail with exit 2 on machines without + # 3.11 even though the `python` stage reported success (issue #50769). + $resolved = Resolve-AvailablePythonVersion + if ($resolved -and $resolved -ne $PythonVersion) { + Write-Info "Python $PythonVersion not available; using detected Python $resolved" + $script:PythonVersion = $resolved + } + Write-Info "Creating virtual environment with Python $PythonVersion..." Push-Location $InstallDir