How to Build a Combo with a Custom Strategy in OmniRoute Dashboard
You can build a combo with a custom strategy in the OmniRoute dashboard by selecting "Custom" in the Strategy dropdown, entering your strategy identifier, then registering a matching handler function in strategyDispatch.ts that returns an ordered list of targets.
A Combo in OmniRoute groups multiple provider-model targets and routes requests through a configurable strategy that determines which target gets invoked. The dashboard lets operators create combos using built-in strategies like priority, random, weighted, and auto—or define custom routing strategies tailored to specific workload requirements. According to the OmniRoute source code, the strategy system is built around a pluggable dispatcher that decouples the UI configuration from the execution logic.
How Combos and Strategies Work Together
The combo architecture separates configuration from execution across four distinct layers. Understanding this flow is essential before implementing a custom strategy.
| Layer | Purpose | Key Source File |
|---|---|---|
| Combo definition | Stores static configuration (name, providers, strategy, timeouts) in the database and materializes it per-request | [comboSetup.ts](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/open-sse/services/combo/comboSetup.ts) |
| Strategy resolution | Normalizes the raw strategy string via normalizeRoutingStrategy, allowing custom identifiers to pass through |
src/shared/constants/routingStrategies.ts (imported in comboSetup.ts) |
| Target ordering | Builds an ordered target list according to the resolved strategy; custom strategies use the same plugin point | [targetResolution.ts](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/open-sse/services/combo/targetResolution.ts) |
| Strategy dispatch | Contains a registry of handlers; adding a custom strategy means registering a new function returning ResolvedComboUnit[] |
[strategyDispatch.ts](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/open-sse/services/combo/strategyDispatch.ts) |
| Live UI feedback | Reduces WebSocket events into a serializable model that drives the React-Flow graph in the Routing Studio | [comboFlowModel.ts](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/src/app/(dashboard)/dashboard/combos/live/comboFlowModel.ts) |
Custom Strategy Execution Flow
When you build a combo with a custom strategy in the OmniRoute dashboard, the backend processes it through this pipeline:
- User input — The dashboard's Strategy field accepts any string value
- Normalization —
normalizeRoutingStrategymaps the string to a known identifier; unrecognized strings become custom keys - Dispatch —
strategyDispatch.tslooks up the key in its registry - Execution — The handler returns an ordered
ResolvedComboUnit[]list that feeds the downstream executor
The dispatcher is implemented as a plain JavaScript object, so adding a new strategy requires no changes to the routing engine—only a new registry entry.
Step-by-Step: Building a Combo with Custom Strategy
Follow these steps to build a combo with a custom strategy in the OmniRoute dashboard:
-
Access the dashboard — Navigate to
http://localhost:20128/dashboard(or your configured port) -
Open the Combos section — Select Combos → Live from the left navigation
-
Create a new combo — Click + New Combo
-
Configure combo metadata
- Name: Enter a unique identifier
- Providers / Models: Add the provider-model pairs to include
- Strategy: Select Custom from the dropdown, then type your strategy identifier (e.g.,
my-fair-share)
-
Save the combo — Click Create to persist to the database
-
Edit as needed — Use the pencil icon to modify the strategy field, then Update
-
Monitor live traffic — Open the Routing Studio view to see your custom strategy in action as a flow graph
Important: The dashboard accepts any custom identifier, but requests will fail unless a matching handler exists in
strategyDispatch.ts.
Implementing a Custom Strategy Handler
To make your custom strategy functional, register a handler in strategyDispatch.ts. Below is a complete example implementing a "fair-share" strategy that rotates through targets evenly.
// File: open-sse/services/combo/strategyDispatch.ts
import type { ResolvedComboUnit } from "./targetResolution";
const customStrategyHandlers: Record<
string,
(units: ResolvedComboUnit[]) => ResolvedComboUnit[]
> = {
// Existing built-in handlers...
"fair-share": (units) => {
// Round-robin based on current second
const now = Date.now();
const index = Math.floor(now / 1000) % units.length;
return [units[index]];
},
};
/**
* Dispatches strategy name to appropriate handler.
* Unknown strategies fall back to built-in priority strategy.
*/
export function dispatchStrategy(
strategy: string,
units: ResolvedComboUnit[]
): ResolvedComboUnit[] {
if (customStrategyHandlers[strategy]) {
return customStrategyHandlers[strategy]!(units);
}
// Default handling for built-in strategies...
return defaultStrategyDispatch(strategy, units);
}
How the integration works:
- The UI stores
fair-share(or your custom identifier) in the combo'sstrategyfield phaseComboSetupincomboSetup.tsnormalizes the string during request processingdispatchStrategylocates the handler incustomStrategyHandlersand returns ordered targets- The executor runs the first eligible target from the returned array
Key Source Files for Custom Strategy Development
Summary
Building a combo with a custom strategy in the OmniRoute dashboard involves three core actions:
- Configure in UI — Select "Custom" and enter your strategy identifier when creating or editing a combo
- Register handler — Add a function to
customStrategyHandlersinstrategyDispatch.tsthat implements your routing logic - Validate execution — Use the Routing Studio's live flow graph to confirm your strategy routes traffic as expected
The pluggable dispatcher design keeps the UI-to-core contract stable while allowing unlimited extensibility for operator-defined routing behaviors.
Frequently Asked Questions
What happens if I enter a custom strategy identifier that isn't registered in the backend?
The request will normalize the string through normalizeRoutingStrategy, but dispatchStrategy will fall back to the built-in priority strategy when no matching handler exists in customStrategyHandlers. Your combo will still function, but not with your intended custom logic. Check the logs to confirm your handler is being invoked.
Can I use custom strategies with the live flow visualization in Routing Studio?
Yes. The comboFlowModel.ts reducer processes WebSocket events into a ComboRunModel that displays your custom strategy identifier as the Strategy node in the React-Flow graph. The visualization shows actual routing decisions in real-time regardless of whether the strategy is built-in or custom.
Is there performance overhead when using custom versus built-in strategies?
No measurable overhead. Both custom and built-in strategies execute through the same dispatchStrategy pathway. The only difference is that built-in strategies may have optimized implementations in defaultStrategyDispatch, while custom strategies run your registered handler function. The target resolution and execution phases remain identical.
How do I update a custom strategy without restarting the OmniRoute service?
The customStrategyHandlers registry is evaluated at request time, not at startup. If your deployment supports hot-reloading of TypeScript/JavaScript modules (or you're running in development mode with file watching), updating strategyDispatch.ts will apply to subsequent requests immediately. For production deployments, a rolling restart is required unless using a dynamic module loader.
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 →