From 87fca8342a2227c305712883e68e2c97f620ffaa Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Fri, 8 May 2026 11:55:15 -0700 Subject: [PATCH] fix(windows installer): UTF-8 BOM, tiered extras, skip tinker-atropos by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit install.ps1 had three related problems that compounded into `hermes dashboard` failing to boot on Windows with 'No module named fastapi': 1. UTF-8 BOM missing. Windows PowerShell 5.1 (the default on Windows 10/11, which is what `irm | iex` runs under) reads files without a BOM as cp1252. install.ps1 has em-dashes, arrows, check marks, etc. — PS 5.1 mangled them and the file failed to parse. Added UTF-8 BOM so PS 5.1, PS 7, and the in-memory `irm | iex` path all read the file identically. 2. `uv pip install -e .[all]` had a single-tier silent fallback to bare `.` on any failure, with `2>&1 | Out-Null` swallowing the error. Any transient extras install failure (network hiccup, wheel build issue, etc.) would drop every optional extra including [web], and the installer would still print 'Main package installed'. Replaced with a four-tier fallback (.[all] -> PyPI-only extras -> dashboard+core -> bare) that prints output at every step and a targeted [web] verify+repair at the end so `hermes dashboard` specifically is never silently broken. 3. tinker-atropos was installed unconditionally after the main install. tinker-atropos/pyproject.toml pulls atroposlib and tinker from git+https://github.com/... which can fail on locked-down networks, flaky DNS, or rate-limited github.com and would half-install the venv. install.sh already skipped it by default with a one-liner for users who actually do RL training — install.ps1 now matches that behavior. Parse-checked clean under Windows PowerShell 5.1.26100.8115 (5318 tokens, 0 parse errors). --- scripts/install.ps1 | 88 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/scripts/install.ps1 b/scripts/install.ps1 index d390d8fae0..2f24ea8970 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -1,4 +1,4 @@ -# ============================================================================ +# ============================================================================ # Hermes Agent Installer for Windows # ============================================================================ # Installation script for Windows (PowerShell). @@ -794,26 +794,78 @@ function Install-Dependencies { $env:VIRTUAL_ENV = "$InstallDir\venv" } - # Install main package with all extras - try { - & $UvCmd pip install -e ".[all]" 2>&1 | Out-Null - } catch { - & $UvCmd pip install -e "." | Out-Null + # Install main package. Tiered fallback so a single flaky git+https dep + # (atroposlib / tinker in the [rl] extra) doesn't silently drop + # dashboard/MCP/cron/messaging extras. Each tier's stdout/stderr is + # preserved — no Out-Null swallowing — so the user can see what failed. + # + # Tier 1: [all] — everything, including RL git+https deps (best case). + # Tier 2: [core-extras] synthesised locally — all PyPI-only extras we + # ship (web, mcp, cron, cli, voice, messaging, slack, dev, acp, + # pty, homeassistant, sms, tts-premium, honcho, google, mistral, + # bedrock, dingtalk, feishu, modal, daytona, vercel). Drops [rl] + # and [matrix] (linux-only) which are the usual failure culprits. + # Tier 3: [web,mcp,cron,cli,messaging,dev] — the minimum we strongly + # believe a user expects `hermes dashboard` / slash commands / + # cron / messaging platforms to work out of the box. + # Tier 4: bare `.` — last-resort so at least the core CLI launches. + $installTiers = @( + @{ Name = "all (with RL/matrix extras)"; Spec = ".[all]" }, + @{ Name = "PyPI-only extras (no git deps)"; Spec = ".[web,mcp,cron,cli,voice,messaging,slack,dev,acp,pty,homeassistant,sms,tts-premium,honcho,google,mistral,bedrock,dingtalk,feishu,modal,daytona,vercel]" }, + @{ Name = "dashboard + core platforms"; Spec = ".[web,mcp,cron,cli,messaging,dev]" }, + @{ Name = "core only (no extras)"; Spec = "." } + ) + $installed = $false + foreach ($tier in $installTiers) { + Write-Info "Trying tier: $($tier.Name) ..." + & $UvCmd pip install -e $tier.Spec + if ($LASTEXITCODE -eq 0) { + Write-Success "Main package installed ($($tier.Name))" + $script:InstalledTier = $tier.Name + $installed = $true + break + } + Write-Warn "Tier '$($tier.Name)' failed (exit $LASTEXITCODE). Trying next tier..." + } + if (-not $installed) { + throw "Failed to install hermes-agent package even with no extras. Inspect the uv pip install output above." + } + + # Verify the dashboard deps specifically — they're the most common thing + # users hit and lazy-import errors from `hermes dashboard` are confusing. + # If tier 1 failed (the common case), [web] was still picked up by tiers + # 2-3; only tier 4 leaves you without it. + $pythonExe = if (-not $NoVenv) { "$InstallDir\venv\Scripts\python.exe" } else { (& $UvCmd python find $PythonVersion) } + if (Test-Path $pythonExe) { + $webOk = $false + try { + & $pythonExe -c "import fastapi, uvicorn" 2>&1 | Out-Null + if ($LASTEXITCODE -eq 0) { $webOk = $true } + } catch { } + if (-not $webOk) { + Write-Warn "fastapi/uvicorn not importable — `hermes dashboard` will not work." + Write-Info "Attempting targeted install of [web] extra as last resort..." + & $UvCmd pip install -e ".[web]" + if ($LASTEXITCODE -eq 0) { + Write-Success "[web] extra installed; `hermes dashboard` should now work." + } else { + Write-Warn "Could not install [web] extra. Run manually: uv pip install --python `"$pythonExe`" `"fastapi>=0.104,<1`" `"uvicorn[standard]>=0.24,<1`"" + } + } } - Write-Success "Main package installed" - - # Install optional submodules - Write-Info "Installing tinker-atropos (RL training backend)..." + # tinker-atropos (RL training) is optional and OFF by default. Matches the + # Linux/macOS install.sh behavior. Reasons not to auto-install: + # - tinker-atropos/pyproject.toml pulls atroposlib + tinker from git+https + # (NousResearch/atropos + thinking-machines-lab/tinker) which can fail on + # locked-down networks, flaky DNS, or rate-limited github.com and would + # previously kill the whole install mid-flight on Windows. + # - It's an RL training submodule, not part of the default agent surface. + # Users who don't do RL training never need it. + # Users who do want it can run the one-liner we print below. if (Test-Path "tinker-atropos\pyproject.toml") { - try { - & $UvCmd pip install -e ".\tinker-atropos" 2>&1 | Out-Null - Write-Success "tinker-atropos installed" - } catch { - Write-Warn "tinker-atropos install failed (RL tools may not work)" - } - } else { - Write-Warn "tinker-atropos not found (run: git submodule update --init)" + Write-Info "tinker-atropos submodule found — skipping install (optional, for RL training)" + Write-Info " To install later: $UvCmd pip install -e `".\tinker-atropos`"" } Pop-Location