How the OmniRoute Auto-Combo 12-Factor Scoring Engine Evaluates Candidate Providers
The OmniRoute Auto-Combo engine uses a 12-factor weighted scoring system in open-sse/services/autoCombo/scoring.ts that normalizes infrastructure signals—quota, health, cost, latency, task fit, and more—into a 0-to-1 score to rank LLM provider candidates.
The Auto-Combo engine is OmniRoute's intelligent routing layer that dynamically selects the optimal LLM provider, model, and connection-account combination for each incoming request. Rather than relying on static rules, it computes a quantitative fitness score for every candidate using twelve normalized factors and a configurable weight vector. This article breaks down exactly how factor extraction and weighted aggregation work inside the OmniRoute codebase.
The Two-Stage Scoring Pipeline
Provider evaluation happens in two distinct phases:
- Factor extraction —
calculateFactors()ingests raw telemetry and metadata from eachProviderCandidate, producing normalized values between 0 and 1. - Weighted aggregation —
calculateScore()multiplies each factor by its corresponding weight and sums the results, returning a final score clamped to[0, 1].
The top-scoring candidate wins the request. If multiple candidates tie, secondary sort keys (latency, then randomization) break the deadlock.
The 12 I²-Factors Explained
All twelve factors are normalized by clamp01() to prevent malformed telemetry from poisoning rankings.
| Factor | Definition | Data Source | Normalization Formula |
|---|---|---|---|
| quota | Remaining quota percentage | candidate.quotaRemaining |
quotaRemaining / 100 |
| health | Circuit-breaker health state | candidate.circuitBreakerState |
1 = CLOSED, 0.5 = HALF_OPEN, 0 = OPEN |
| costInv | Inverse cost (cheaper → higher) | candidate.costPer1MTokens vs pool max |
1 - (cost / maxCost) |
| latencyInv | Inverse p95 latency (faster → higher) | candidate.p95LatencyMs vs pool max |
1 - (latency / maxLatency) |
| taskFit | Model-task compatibility | getTaskFitness(model, taskType) |
Static table lookup, clamped 0-1 |
| stability | Latency consistency (lower jitter → higher) | candidate.latencyStdDev vs pool max |
1 - (stdDev / maxStdDev) |
| tierPriority | Account tier + reset window bonus | accountTier, quotaResetIntervalSecs |
calculateTierScore() |
| tierAffinity | Alignment with minimum tier hint | manifestHint?.recommendedMinTier |
calculateTierAffinity() |
| specificityMatch | Match to manifest specificity hint | manifestHint?.specificity.score |
calculateSpecificityMatch() |
| contextAffinity | Session provider reuse preference | candidate.contextAffinity |
Clamped input or default 0.5 |
| cacheAffinity | Prompt cache key affinity | candidate.cacheAffinity |
Clamped input or default 0 |
| resetWindowAffinity | Preference for soon-resetting quotas | candidate.resetWindowAffinity |
Clamped input or default 0.5 |
| connectionDensity | Inverse connection pool saturation | candidate.connectionPoolSize |
((size - 1) / 10) |
The "I²" designation refers to infrastructure-squared: quota and health are the dominant first-order signals that together receive 35% of default weight allocation.
Core Scoring Implementation
Factor Extraction
// open-sse/services/autoCombo/scoring.ts
export interface ScoringFactors {
quota: number; // [0, 1]
health: number; // [0, 1]
costInv: number; // [0, 1]
latencyInv: number; // [0, 1]
taskFit: number; // [0, 1]
stability: number; // [0, 1]
tierPriority: number; // [0, 1]
tierAffinity: number; // [0, 1]
specificityMatch: number; // [0, 1]
contextAffinity: number; // [0, 1]
cacheAffinity: number; // [0, 1]
resetWindowAffinity: number; // [0, 1]
connectionDensity: number; // [0, 1]
}
calculateFactors() computes each value by comparing the candidate against pool-wide maximums (for cost, latency, stability) or direct metadata lookups (for quota, health, tier).
Weighted Score Calculation
// open-sse/services/autoCombo/scoring.ts
export function calculateScore(
factors: ScoringFactors,
weights: ScoringWeights,
): number {
return clamp01(
weights.quota * factors.quota +
weights.health * factors.health +
weights.costInv * factors.costInv +
weights.latencyInv * factors.latencyInv +
weights.taskFit * factors.taskFit +
weights.stability * factors.stability +
weights.tierPriority * factors.tierPriority +
(weights.tierAffinity ?? 0) * factors.tierAffinity +
(weights.specificityMatch ?? 0) * factors.specificityMatch +
(weights.contextAffinity ?? 0) * factors.contextAffinity +
(weights.cacheAffinity ?? 0) * (factors.cacheAffinity ?? 0) +
(weights.resetWindowAffinity ?? 0) * factors.resetWindowAffinity +
(weights.connectionDensity ?? 0) * factors.connectionDensity,
);
}
Optional weights (marked with ?? 0) activate only when the operator configures them or when a RoutingHint supplies manifest-level guidance.
Default Weight Distribution
The DEFAULT_WEIGHTS constant in scoring.ts establishes the following allocation:
| Weight | Value | Purpose |
|---|---|---|
quota |
0.15 | Prevent quota exhaustion |
health |
0.20 | Avoid unhealthy providers |
costInv |
0.15 | Prefer cheaper options |
latencyInv |
0.12 | Prefer faster options |
taskFit |
0.10 | Match model to task |
stability |
0.08 | Reduce jitter |
tierPriority |
0.12 | Respect account tiers |
tierAffinity |
0.05 | Honor minimum tier hints |
specificityMatch |
0.03 | Honor specificity hints |
contextAffinity |
0.00 | Disabled by default |
cacheAffinity |
0.00 | Disabled by default |
resetWindowAffinity |
0.00 | Disabled by default |
connectionDensity |
0.00 | Disabled by default |
Infrastructure factors (quota, health, costInv, latencyInv) collectively control 62% of the score, giving the engine its "I²" character.
Practical Code Examples
Basic Pool Scoring
import { scorePool, DEFAULT_WEIGHTS } from '@/open-sse/services/autoCombo/scoring';
import { getTaskFitness } from '@/open-sse/services/autoCombo/taskFitness';
// Build candidates from provider catalog
const rawCandidates = await virtualFactory.createVirtualAutoCombo();
// Score for "coding" task using defaults
const ranked = scorePool(rawCandidates, 'coding', DEFAULT_WEIGHTS, getTaskFitness);
console.log(`Top provider: ${ranked[0].provider}/${ranked[0].model}`);
console.log(`Score: ${ranked[0].score.toFixed(4)}`);
Custom Weight Override (Cost-Sensitive Mode)
import { normalizeScoringWeights } from '@/open-sse/services/autoCombo/scoring';
const costSensitiveWeights = normalizeScoringWeights({
quota: 0.20,
health: 0.15,
costInv: 0.35, // Boost cost importance
latencyInv: 0.10, // Deprioritize speed
taskFit: 0.15,
stability: 0.05,
tierPriority: 0.10,
});
const ranked = scorePool(rawCandidates, 'coding', costSensitiveWeights, getTaskFitness);
Single Candidate Evaluation (Testing)
import { calculateFactors, calculateScore } from '@/open-sse/services/autoCombo/scoring';
const candidate: ProviderCandidate = {
provider: 'openai',
model: 'gpt-4-turbo',
quotaRemaining: 78,
circuitBreakerState: 'CLOSED',
costPer1MTokens: 10.00,
p95LatencyMs: 450,
// ... other fields
};
const factors = calculateFactors(candidate, allCandidates, 'coding', getTaskFitness);
const score = calculateScore(factors, DEFAULT_WEIGHTS);
console.log(`Factors:`, factors);
console.log(`Final score: ${score.toFixed(4)}`);
Manifest Hint Integration
import type { RoutingHint } from '@/open-sse/services/autoCombo/manifestAdapter';
const hint: RoutingHint = {
recommendedMinTier: 'ultra', // Activates tierAffinity
specificity: {
score: 85, // Activates specificityMatch
dimensions: ['reasoning', 'code']
}
};
const ranked = scorePool(
rawCandidates,
'coding',
DEFAULT_WEIGHTS,
getTaskFitness,
hint // Optional 4th parameter
);
Entry Point and Integration
The scorePool() function is invoked by autoCombo strategy implementation in open-sse/services/autoCombo/index.ts. This is the public API consumed by OmniRoute's routing layer:
// open-sse/services/autoCombo/index.ts (simplified)
export async function autoComboRoute(
request: LLMRequest,
context: RoutingContext,
): Promise<ProviderSelection> {
const candidates = await virtualFactory.createVirtualAutoCombo();
const taskType = classifyTask(request);
const scored = scorePool(
candidates,
taskType,
context.weights ?? DEFAULT_WEIGHTS,
getTaskFitness,
context.manifestHint,
);
return {
provider: scored[0].provider,
model: scored[0].model,
connectionAccount: scored[0].connectionAccount,
score: scored[0].score,
};
}
Key Source Files
| File | Role |
|---|---|
open-sse/services/autoCombo/scoring.ts |
Core factor extraction, calculateScore(), scorePool(), weight normalization |
open-sse/services/autoCombo/index.ts |
Public entry point integrating with routing layer |
open-sse/services/autoCombo/virtualFactory.ts |
Candidate pool construction via createVirtualAutoCombo() |
open-sse/services/autoCombo/taskFitness.ts |
Static model-task compatibility matrix |
open-sse/services/autoCombo/manifestAdapter.ts |
RoutingHint type definitions and parsing |
open-sse/handlers/autoComboCandidates.ts |
Read-only API decorating candidates with reachability state |
Summary
- The OmniRoute Auto-Combo 12-factor scoring engine evaluates every provider candidate across quota, health, cost, latency, task fit, stability, tier priority, tier affinity, specificity match, context affinity, cache affinity, reset window affinity, and connection density.
- Factors are normalized to [0, 1] and combined via weighted summation in
calculateScore(). - Default weights prioritize infrastructure signals (62% combined), with quota (15%) and health (20%) as the dominant "I²" factors.
- The engine supports runtime weight customization and manifest-driven hints for fine-grained routing control.
- All scoring logic lives in
open-sse/services/autoCombo/scoring.tsand is invoked throughscorePool()by the routing layer.
Frequently Asked Questions
What does "I²-factor" mean in OmniRoute's scoring engine?
"I²-factor" refers to the two infrastructure-level factors that dominate the default weight distribution: quota availability (15%) and health/circuit-breaker state (20%). Together these "infrastructure-squared" signals control 35% of the scoring decision, ensuring the engine prioritizes providers that are both well-capitalized and operationally healthy before considering cost or latency optimizations.
How can I customize which factors matter most for my workload?
Override the DEFAULT_WEIGHTS by calling normalizeScoringWeights() with a partial weight object. Pass your custom weights as the third argument to scorePool(). The function automatically renormalizes so weights sum to 1.0. For UI-driven changes, store weights in your deployment configuration and inject them via the RoutingContext.
Why are some factors like cacheAffinity and contextAffinity zero by default?
These factors represent optional affinity optimizations that make sense only in specific deployment patterns. cacheAffinity requires prompt-key caching infrastructure; contextAffinity assumes sticky session routing. Keeping them at 0.00 in DEFAULT_WEIGHTS ensures safe, stateless behavior out of the box while allowing operators to opt into affinity-based routing when their architecture supports it.
How does the engine handle missing or malformed candidate telemetry?
All factor calculations pass through clamp01(), which bounds every intermediate result to [0, 1]. For pool-relative factors like costInv and latencyInv, the engine computes maximums across the candidate set, so a single outlier cannot collapse the scale. Missing optional fields (e.g., connectionPoolSize) receive sensible defaults that neutralize their impact on the final score.
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 →