OmniRoute Combo Routing System Architecture: A Deep Dive Into Multi‑Provider LLM Resilience
OmniRoute's combo routing system is a modular, multi-stage pipeline that distributes requests across LLM providers using configurable strategies, applies circuit-breaker and cooldown-based resilience logic, and validates response quality before returning results.
The combo routing layer sits at the heart of the OmniRoute open-source gateway. It transforms a single API request into an orchestrated sequence of provider attempts—automatically handling fallbacks, retries, and quality checks. This article examines the complete architecture, from request entry through final response, based on the actual source code in release v3.8.50.
The 10-Stage Combo Routing Pipeline
OmniRoute processes every combo request through a strictly ordered pipeline. Each stage is implemented in a dedicated module with clear responsibilities:
| Stage | Module | Core Function |
|---|---|---|
| 1 | open-sse/handlers/chatCore.ts |
Entry point validation |
| 2 | combo/context.ts |
Context assembly |
| 3 | combo/dispatchPrelude.ts |
Pre-dispatch shortcuts |
| 4 | combo/comboSetup.ts |
Auto-candidate generation |
| 5 | combo/comboStructure.ts |
Target resolution |
| 6 | combo/shadowRouting.ts |
Shadow routing |
| 7 | combo.ts |
Main execution loop |
| 8 | combo/cooldownRetry.ts |
Fallback orchestration |
| 9 | comboMetrics.ts |
Observability |
| 10 | open-sse/utils/error.ts |
Response sanitization |
Request Entry and Context Creation
All combo requests enter through handleComboChat in open-sse/handlers/chatCore.ts. This handler validates the request body, extracts the combo definition, and delegates to the combo engine.
The immediate next step is context creation in combo/context.ts. The createComboContext function packages everything the pipeline needs into a single ComboContext object:
- Original request body
- Combo definition (name, strategy, configuration)
- Resilience settings
- Logger instance
- Provider connection caches
This context object is immutable and passes through every subsequent stage, ensuring consistent state without side effects.
Pre-Dispatch Shortcuts: Pinned, Fusion, and Chaos Modes
Before the generic target loop runs, tryPinnedModelDispatch in combo/dispatchPrelude.ts checks for three special execution modes:
- Pinned-model dispatch — Routes directly to a specific model when session affinity requires it
- Fusion mode — Executes multiple models in parallel and applies a judge to select or merge responses
- Chaos mode — Intentionally fans out to multiple providers simultaneously for redundancy or A/B testing
These shortcuts bypass the standard candidate scoring when the combo configuration explicitly demands deterministic or parallel behavior.
Auto-Candidate Generation: The 13-Factor Scoring Model
When a combo uses the auto strategy, the system dynamically ranks available providers. The buildAutoCandidates function in combo/comboSetup.ts constructs AutoProviderCandidate objects by querying:
- Live provider connection caches
- Real-time quota information
- P95 latency statistics
- Cost-per-token pricing
- Circuit-breaker state
- Hidden-model filters
The actual scoring happens in autoStrategy.ts, which implements a 13-factor model:
// From autoStrategy.ts — simplified scoring weights
const score =
p95LatencyMs * 0.25 +
errorRate * 0.20 +
(1 - quotaRemaining / 100) * 0.15 +
costPer1MTokens * 0.15 +
resetWindowAffinity * 0.10 +
successRate * 0.10 +
circuitBreakerHealth * 0.05;
Higher scores indicate better candidates. The top-scoring providers become the ordered target list.
Target Resolution: From Definitions to Concrete Connections
The resolveComboTargets function in combo/comboStructure.ts transforms abstract combo definitions into executable ResolvedComboTarget[] objects. This stage handles:
- Provider wildcard expansion (e.g.,
"provider": "*"matches all configured providers) - Model name resolution to actual API endpoints
- Connection ID assignment
- Step ID generation for pipeline tracking
- Execution key derivation for telemetry
The output is a fully materialized execution plan with no remaining symbolic references.
The Main Target Loop: Resilience in Action
The executeTarget function in combo.ts iterates over resolved targets, applying a comprehensive resilience stack at each attempt:
// Pseudocode representing the executeTarget checks
async function executeTarget(context, target) {
// 1. Circuit breaker check
if (isProviderCircuitOpen(target.provider)) return skip;
// 2. Connection cooldown check
if (isProviderInCooldown(target.connectionId)) return skip;
// 3. Model lockout check
if (isModelLocked(target.model)) return skip;
// 4. Quota exhaustion check
if (isQuotaExhausted(target)) return skip;
// 5. Credential validation
if (!credentialGate(target)) return skip;
// 6. Concurrency semaphore acquire
await rateLimitSemaphore.acquire(target);
// 7. Predictive TTFT zero-latency path
if (predictiveTtftAvailable(target)) {
return await predictiveExecute(target);
}
// 8. Standard execution with reasoning-token buffering
const response = await executeWithReasoningBuffer(target);
// 9. Proactive compression for fallback readiness
await prepareCompressionFallback(response);
// 10. Quality validation
if (!validateResponseQuality(response)) {
releasePin(target);
return failure; // Triggers next target
}
return response;
}
Each check consults a dedicated subsystem:
| Check | Source File | Purpose |
|---|---|---|
| Circuit breaker | circuitBreaker.ts |
Halt traffic to failing providers |
| Connection cooldown | providerCooldownTracker.ts |
Respect 429 retry-after headers |
| Model lockout | quotaExhaustionCutoff.ts |
Disable specific models per connection |
| Credential gate | credentialGate.ts |
Validate API key permissions |
| Rate limit semaphore | rateLimitSemaphore.ts |
Enforce global concurrency limits |
| Compression strategy | compression/strategySelector.ts |
Prepare fallback-compressed requests |
Fallback, Retry, and Recovery Orchestration
When a target fails, the combo routing system consults resolveComboCooldownWaitDecision in combo/cooldownRetry.ts. This function implements three recovery paths:
- Immediate retry — Re-attempt the same target (up to
maxRetries) - Cooldown-aware wait — Pause execution based on
Retry-Afterheaders, then retry the full target set - Diagnostic error return — Exhaustion path with structured recovery hints
The pinRecovery.ts module generates recovery hints for sticky sessions. When a pinned model fails, it suggests alternatives like:
"Increase
max_tokens— reasoning model exhausted token budget"
or
"Provider cooldown expires in 47s; consider
fallbackDelayMs: 5000"
Quality Guardrails Beyond HTTP Status Codes
OmniRoute treats HTTP 200 ≠ success. The validateResponseQuality function in combo/validateQuality.ts inspects every successful response for:
- Empty content
- Disallowed token patterns
- Schema violations (when
responseValidationis enabled) - Streaming truncation indicators
Failed quality checks trigger the same fallback logic as provider errors, with the additional step of pin release—allowing subsequent requests to route away from the degraded model.
Shadow Routing and Observability
The scheduleShadowRouting function in combo/shadowRouting.ts optionally dispatches duplicate requests to secondary targets. These shadow executions:
- Do not block the primary response
- Record latency and success metrics
- Enable provider performance comparison without user impact
Primary metrics collection happens in comboMetrics.ts, which aggregates per-target data including:
- Attempt order and outcome
- Excluded providers and exclusion reasons
- Fallback counts and recovery hints
All errors flow through errorResponseWithComboDiagnostics in open-sse/utils/error.ts, ensuring no stack traces leak while providing structured debugging information.
Configuring a Combo: API and Code Examples
Dashboard/JSON Definition
{
"name": "quick-search-combo",
"strategy": "auto",
"models": [
{ "provider": "openai", "model": "gpt-4o-mini" },
{ "provider": "anthropic", "model": "claude-sonnet-4.6" },
{ "provider": "google", "model": "gemini-2.5-flash" }
],
"config": {
"maxRetries": 2,
"fallbackDelayMs": 0,
"predictiveTtftMs": 300,
"responseValidation": true
}
}
Client Invocation
curl -X POST http://localhost:20128/v1/chat/completions \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "quick-search-combo",
"messages": [{"role": "user", "content": "Explain quantum tunneling."}],
"max_tokens": 500
}'
Custom Strategy Extension
// open-sse/services/combo/autoStrategy.ts
export const scoreAutoTargets = (candidates: AutoProviderCandidate[]) => {
return candidates.map(c => ({
...c,
score:
c.p95LatencyMs * 0.35 +
c.errorRate * 0.25 +
(1 - c.quotaRemaining / 100) * 0.20 +
c.costPer1MTokens * 0.15 +
(c.usageCount ?? 0) * -0.05 // Prefer less-used providers
}));
};
Recompile to activate the new factor across all auto strategy combos.
Summary
- OmniRoute combo routing implements a 10-stage pipeline for resilient multi-provider LLM requests
- Auto-candidate generation uses 13-factor scoring including latency, cost, quota, and circuit-breaker state
- Three resilience layers—circuit breaker, connection cooldown, and model lockout—operate inside the main execution loop
- Quality validation rejects HTTP 200 responses that fail content guardrails
- Shadow routing enables passive observability without latency impact
- 19 built-in strategies include priority, weighted, round-robin, cost-optimized, and context-relay modes
Frequently Asked Questions
What makes OmniRoute's combo routing different from simple load balancing?
Simple load balancers distribute requests based on health checks and round-robin policies. OmniRoute's combo routing adds provider-aware scoring (13 factors), proactive resilience (circuit breakers, cooldowns, model lockouts), and semantic quality validation that treats malformed 200 responses as failures. The architecture specifically handles LLM-specific failure modes like quota exhaustion and reasoning-token limits.
How does the auto strategy select which provider to use?
The auto strategy in autoStrategy.ts calculates a composite score for every routable provider connection. It weighs P95 latency (25%), recent error rate (20%), remaining quota percentage (15%), cost per million tokens (15%), reset-window affinity (10%), historical success rate (10%), and circuit-breaker health (5%). The highest-scoring candidates become the ordered target list.
Can I force a specific model for certain request types?
Yes. Use pinned-model dispatch by including a pinnedModel field in your combo configuration or session context. The tryPinnedModelDispatch function in dispatchPrelude.ts routes directly to the specified model before any scoring occurs. If that model fails, standard fallback logic applies unless strict pinning is enabled.
What recovery options exist when all providers in a combo fail?
When targets exhaust, pinRecovery.ts generates structured recovery hints. These may suggest increasing max_tokens, waiting for cooldown expiration, switching to a different combo, or adjusting fallbackDelayMs. The errorResponseWithComboDiagnostics function returns these hints alongside attempt history and excluded provider reasons, enabling client-side retry decisions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →