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:

  1. User input — The dashboard's Strategy field accepts any string value
  2. NormalizationnormalizeRoutingStrategy maps the string to a known identifier; unrecognized strings become custom keys
  3. DispatchstrategyDispatch.ts looks up the key in its registry
  4. 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:

  1. Access the dashboard — Navigate to http://localhost:20128/dashboard (or your configured port)

  2. Open the Combos section — Select CombosLive from the left navigation

  3. Create a new combo — Click + New Combo

  4. 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)
  5. Save the combo — Click Create to persist to the database

  6. Edit as needed — Use the pencil icon to modify the strategy field, then Update

  7. 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's strategy field
  • phaseComboSetup in comboSetup.ts normalizes the string during request processing
  • dispatchStrategy locates the handler in customStrategyHandlers and returns ordered targets
  • The executor runs the first eligible target from the returned array

Key Source Files for Custom Strategy Development

File Purpose Location
comboSetup.ts Request context setup, strategy resolution, combo-wide settings [open-sse/services/combo/comboSetup.ts](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/open-sse/services/combo/comboSetup.ts)
targetResolution.ts Candidate target building and strategy application [open-sse/services/combo/targetResolution.ts](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/open-sse/services/combo/targetResolution.ts)
strategyDispatch.ts Registry and dispatcher for all routing strategies [open-sse/services/combo/strategyDispatch.ts](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/open-sse/services/combo/strategyDispatch.ts)
comboFlowModel.ts WS event reducer for Routing Studio visualization src/app/(dashboard)/dashboard/combos/live/comboFlowModel.ts
autoStrategy.ts Session-scoped identifier helper for strategy extensions [open-sse/services/combo/autoStrategy.ts](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.51/open-sse/services/combo/autoStrategy.ts)

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 customStrategyHandlers in strategyDispatch.ts that 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →