LLM fallback chain
Each alert is triaged by a 5-model chain (OpenRouter, all free). If the primary model rate-limits (429) or is missing (404), Remo tries the next:
nvidia/nemotron-3-super-120b-a12b:freemeta-llama/llama-3.3-70b-instruct:freeqwen/qwen3-coder:freenvidia/nemotron-3-nano-30b-a3b:freeopenai/gpt-oss-20b:free
The tenant’s preferred model goes first, then the chain.
Structured output
The LLM must answer with strict JSON:
{
"severity_assessment": "critical|high|medium|low",
"diagnosis": "2-3 sentences",
"probable_cause": "string",
"impact": "string",
"recommended_actions": ["..."],
"escalation_needed": true,
"confidence": 0.85
}
Severity is re-assessed by impact, not just what the monitor said.
Cache-first
Repeated alerts hit the KV cache (computeCacheKey(tenant, parsed)), reusing
the last diagnosis (TTL default 1h). Saves tokens and keeps latency low.
Enrichment (R-007)
For DB alerts, Remo pulls live context from Bonito before triage so the diagnosis is precise (exact PID, query text, baseline):
isDBAlert()matchespostgres|mysql|mongo|deadlock|slow_query|lock|blocking|regression...- fetches
bonito-api/queries/top,/locks/active,/baseline/{fp} - appends an
ENRICHMENT DATAblock to the LLM prompt
Failure-safe: 3s timeout + Promise.allSettled — if Bonito is unreachable,
triage runs without enrichment (the alert is never blocked or lost).
# tenant config
enrichment:
enabled: true
bonito_endpoint: https://bonito-api.sofe.dev
bonito_api_key: <key>
bonito_timeout_ms: 3000
Example enriched diagnosis: “PID 829705 holding transactionid lock, blocking PID 829718.
pg_cancel_backend(829705);·CREATE INDEX idx_orders_id ON orders(id);”