Parte 2 de 4
OmniRoute portable + combo best-free-coding
Instalamos OmniRoute en el SSD con Node 22 portable, configuramos la key de OpenRouter y creamos el combo best-free-coding con 3 modelos gratis y fallback automático.
Quería modelos de terceros (OpenRouter, Nemotron, DeepSeek) con fallback automático si uno falla o agota cuota, todo portable en el SSD. La solución: OmniRoute como gateway único + combo best-free-coding con estrategia priority.
Qué necesitamos
- SSD en
J:(exFAT/NTFS) - Node.js ≥ 22.22.2 para OmniRoute 3.8.x (el host tiene Node 20 → usaremos Node 22 portable en
J:\node) - Key de OpenRouter (gratis, para modelos
:free) - PowerShell 5.1+
1. Instalar OmniRoute portable en J:\omniroute
# Desde el host (Node 20 + npm) — solo para descargar dependencias
npm install -g --prefix "J:\omniroute" omniroute
# → crea J:\omniroute\node_modules\omniroute\bin\omniroute.mjs (v3.8.49)
Por qué
--prefix: instala todo dentro deJ:\omniroute, sin tocar%APPDATA%.
2. Node 22 portable (soluciona el crash 0xC0000005)
OmniRoute 3.8.x requiere Node ≥22.22.2. El host tiene Node 20.15 → crash de acceso a memoria (better-sqlite3 nativo). Solución portable: bajar Node 22 standalone al SSD.
New-Item -ItemType Directory -Path "J:\node" -Force
Invoke-WebRequest -Uri "https://nodejs.org/dist/latest-v22.x/win-x64/node.exe" -OutFile "J:\node\node.exe"
& "J:\node\node.exe" --version
# v22.23.2
Nota:
node.exestandalone (87 MB) no incluye npm. Sirve solo para ejecutar OmniRoute. La instalación de dependencias se hizo arriba con el Node 20 del host.
3. Variables de entorno (.env en J:\omniroute)
# Generar secrets aleatorios
$jwt = [Convert]::ToBase64String((1..36 | ForEach-Object { Get-Random -Maximum 256 }))
$akey = -join ((1..32 | ForEach-Object { '{0:x2}' -f (Get-Random -Maximum 256) }))
@"
DATA_DIR=J:\omniroute\data
JWT_SECRET=$jwt
API_KEY_SECRET=$akey
INITIAL_PASSWORD=CHANGEME
PORT=20128
REQUIRE_API_KEY=false
NODE_ENV=production
"@ | Set-Content -Path "J:\omniroute\.env" -Encoding utf8
DATA_DIR: SQLite con providers/keys/settings viaja en el SSDJWT_SECRET/API_KEY_SECRET: cifran claves en reposo (AES-256-GCM)PORT=20128: gateway exponehttp://localhost:20128/v1(OpenAI-compatible)
4. Arrancar OmniRoute y health-check
# Lanzar en background con Node 22 portable
$proc = Start-Process -FilePath "J:\node\node.exe" `
-ArgumentList "`"J:\omniroute\node_modules\omniroute\bin\omniroute.mjs`"" `
-WorkingDirectory "J:\omniroute" `
-WindowStyle Hidden `
-RedirectStandardOutput "J:\omniroute\server.out.log" `
-RedirectStandardError "J:\omniroute\server.err.log" `
-PassThru
# Health-check con reintentos
$ok = $false
for ($i=0; $i -lt 30; $i++) {
try {
$r = Invoke-RestMethod -Uri "http://localhost:20128/api/health" -TimeoutSec 3 -ErrorAction Stop
Write-Host "HEALTH OK: $($r | ConvertTo-Json -Compress)"
$ok = $true; break
} catch { Start-Sleep -Seconds 5 }
}
if (-not $ok) { Get-Content "J:\omniroute\server.err.log" -Tail 40 }
Deberías ver {"status":"ok"}.
5. Añadir key de OpenRouter (Dashboard web)
Abre http://localhost:20128 en el navegador → Providers → OpenRouter → pega tu key sk-or-v1-... (gratis, solo modelos :free).
La key se guarda cifrada en
J:\omniroute\data\provider-credentials.json. No la pongas en el repo ni en el tutorial.
6. Crear combo best-free-coding (3 modelos, estrategia priority)
$combo = @{
name = "best-free-coding"
strategy = "priority"
models = @(
"oc/nemotron-3-ultra-free"
"oc/deepseek-v4-flash-free"
"oc/big-pickle"
)
config = @{
maxRetries = 1
fallbackDelayMs = 0
}
} | ConvertTo-Json -Depth 4 -Compress
Invoke-RestMethod -Method Post -Uri "http://localhost:20128/api/combos" `
-ContentType "application/json" -Body $combo
Orden = prioridad. Si el 1º devuelve 429/402/5xx, salta al 2º, luego al 3º. Cero coste (todos gratis).
7. Configurar opencode para usar OmniRoute
Edita J:\opencode\config\opencode.jsonc (o donde tengas tu config):
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"omniroute": {
"npm": "@ai-sdk/openai-compatible",
"baseURL": "http://localhost:20128/v1",
"apiKey": "sk_omniroute", // dummy, OmniRoute ignora la key si REQUIRE_API_KEY=false
"models": {
"best-free-coding": {}
}
}
},
"model": "omniroute/best-free-coding"
}
apiKeyes un placeholder; conREQUIRE_API_KEY=falseOmniRoute no la valida.
8. Actualizar lanzadores para auto-arrancar OmniRoute
J:\opencode.ps1 (añadir al principio):
# Auto-arrancar OmniRoute si no responde
$omnirouteProc = $null
function Start-OmniRouteIfNeeded {
try { Invoke-RestMethod -Uri "http://localhost:20128/api/health" -TimeoutSec 2 -ErrorAction Stop | Out-Null }
catch {
Write-Host "Iniciando OmniRoute..." -ForegroundColor Yellow
$omnirouteProc = Start-Process -FilePath "J:\node\node.exe" `
-ArgumentList "`"J:\omniroute\node_modules\omniroute\bin\omniroute.mjs`"" `
-WorkingDirectory "J:\omniroute" -WindowStyle Hidden `
-RedirectStandardOutput "J:\omniroute\server.out.log" `
-RedirectStandardError "J:\omniroute\server.err.log" -PassThru
Start-Sleep -Seconds 8
# health-check rápido
for ($i=0; $i -lt 10; $i++) {
try { Invoke-RestMethod -Uri "http://localhost:20128/api/health" -TimeoutSec 2 -ErrorAction Stop | Out-Null; break }
catch { Start-Sleep -Seconds 2 }
}
}
}
Start-OmniRouteIfNeeded
# ... resto del lanzador (variables OPENCODE_*, PATH, opencode.exe)
J:\opencode.bat (equivalente en batch al inicio).
9. Verificación
J:\opencode.ps1 models omniroute
# Debe listar los 3 modelos del combo
J:\opencode.ps1 run "Hola, ¿qué modelo eres?"
# Respuesta real vía gateway; cabecera X-OmniRoute-Decision indica cuál sirvió
Forzar fallback: en Dashboard → Providers → desactiva Nemotron → repite el chat → debe saltar a DeepSeek.
Problemas y lecciones
Lección: Node 22 portable = portabilidad real
Ambos PCs usanJ:\node\node.exe. Da igual qué Node tengan instalado localmente. El SSD lo lleva todo.
Lección:
runtime repairfalla sin toolchain C++
El comando integradoomniroute runtime repairnecesita compilarbetter-sqlite3. Node portable standalone evita el problema.
Lección: Sin internet → built-ins siguen
Si no hay red, OmniRoute arranca pero los providers fallan. Los modelosopencode/*-free(integrados) siguen funcionando como respaldo manual.
Algo que aprendimos por las malas: crash 0xC0000005 en Node 20
No es bug de OmniRoute, es incompatibilidad debetter-sqlite3nativo con Node <22. La solución portable (Node 22 en el SSD) es la más limpia.
Qué sigue
Tenemos gateway con fallback automático entre 3 modelos gratis. En la siguiente parte configuramos OpenRouter en detalle (modelos :free, límites, uso práctico con /connect y /models).