fix(windows installer): UTF-8 BOM, tiered extras, skip tinker-atropos by default

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).
This commit is contained in:
Teknium 2026-05-08 11:55:15 -07:00
parent acc0a81624
commit 87fca8342a

View file

@ -1,4 +1,4 @@
# ============================================================================ # ============================================================================
# Hermes Agent Installer for Windows # Hermes Agent Installer for Windows
# ============================================================================ # ============================================================================
# Installation script for Windows (PowerShell). # Installation script for Windows (PowerShell).
@ -794,26 +794,78 @@ function Install-Dependencies {
$env:VIRTUAL_ENV = "$InstallDir\venv" $env:VIRTUAL_ENV = "$InstallDir\venv"
} }
# Install main package with all extras # Install main package. Tiered fallback so a single flaky git+https dep
try { # (atroposlib / tinker in the [rl] extra) doesn't silently drop
& $UvCmd pip install -e ".[all]" 2>&1 | Out-Null # dashboard/MCP/cron/messaging extras. Each tier's stdout/stderr is
} catch { # preserved — no Out-Null swallowing — so the user can see what failed.
& $UvCmd pip install -e "." | Out-Null #
# 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."
} }
Write-Success "Main package installed" # Verify the dashboard deps specifically — they're the most common thing
# users hit and lazy-import errors from `hermes dashboard` are confusing.
# Install optional submodules # If tier 1 failed (the common case), [web] was still picked up by tiers
Write-Info "Installing tinker-atropos (RL training backend)..." # 2-3; only tier 4 leaves you without it.
if (Test-Path "tinker-atropos\pyproject.toml") { $pythonExe = if (-not $NoVenv) { "$InstallDir\venv\Scripts\python.exe" } else { (& $UvCmd python find $PythonVersion) }
if (Test-Path $pythonExe) {
$webOk = $false
try { try {
& $UvCmd pip install -e ".\tinker-atropos" 2>&1 | Out-Null & $pythonExe -c "import fastapi, uvicorn" 2>&1 | Out-Null
Write-Success "tinker-atropos installed" if ($LASTEXITCODE -eq 0) { $webOk = $true }
} catch { } catch { }
Write-Warn "tinker-atropos install failed (RL tools may not work)" 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 { } else {
Write-Warn "tinker-atropos not found (run: git submodule update --init)" Write-Warn "Could not install [web] extra. Run manually: uv pip install --python `"$pythonExe`" `"fastapi>=0.104,<1`" `"uvicorn[standard]>=0.24,<1`""
}
}
}
# 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") {
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 Pop-Location