# How OmniRoute Registers 237 AI Providers and Implements the Executor Pattern for Request Handling

> Discover how OmniRoute registers 237 AI providers with a proxy registry and implements the Factory plus Strategy executor pattern for efficient request handling. Learn about BaseExecutor and provider-specific classes.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: deep-dive
- Published: 2026-07-08

---

**OmniRoute registers 237 providers through a centralized proxy-based registry in [`src/shared/constants/providers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/providers.ts) and handles requests using a Factory plus Strategy executor pattern where `getExecutor()` instantiates provider-specific classes extending `BaseExecutor`.**

OmniRoute is an open-source AI gateway that unifies access to hundreds of model providers through a single interface. Understanding how the system registers its **237 providers** and delegates requests through the **executor pattern** reveals the architecture that enables seamless multi-provider support. This deep dive examines the source code implementation in the `diegosouzapw/OmniRoute` repository.

## Centralized Provider Registration

OmniRoute maintains a **single source of truth** for every AI provider through a unique lazy-loading registry architecture. Rather than loading all provider definitions at startup, the system uses a JavaScript Proxy to defer catalog access until first use.

### The Proxy-Based Registry

The master file [`src/shared/constants/providers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/providers.ts) exports `AI_PROVIDERS` as a Proxy object that wraps ten distinct catalog modules. When code accesses a provider identifier, the proxy's `get` handler iterates through catalogs to resolve the definition:

```typescript
export const AI_PROVIDERS = new Proxy(
  {} as Record<string, AiProviderDefinition>,
  {
    get(_, id) {
      const catalogs = [
        NOAUTH_PROVIDERS,
        OAUTH_PROVIDERS,
        WEB_COOKIE_PROVIDERS,
        APIKEY_PROVIDERS,
        LOCAL_PROVIDERS,
        SEARCH_PROVIDERS,
        AUDIO_ONLY_PROVIDERS,
        UPSTREAM_PROXY_PROVIDERS,
        CLOUD_AGENT_PROVIDERS,
        SYSTEM_PROVIDERS,
      ];
      for (const cat of catalogs) if (id in cat) return cat[id as string];
      return undefined;
    },
  }
);

```

This design ensures that provider metadata exists in exactly one place while avoiding the memory overhead of loading 237 definitions simultaneously.

### Catalog Organization by Authentication Type

The registry splits providers into semantic categories based on their authentication requirements and capabilities:

- **[`providers/noauth.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/providers/noauth.ts)** – Providers requiring no authentication (e.g., `opencode`, `duckduckgo-web`)
- **[`providers/oauth.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/providers/oauth.ts)** – OAuth-based providers (e.g., `github`, `cursor`, `claude`)
- **[`providers/web-cookie.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/providers/web-cookie.ts)** – Web UI cookie-based providers (e.g., `chatgpt-web`, `gemini-web`)
- **`providers/apikey/*.ts`** – API-key providers organized by family (gateways, frontier labs, inference hosts, enterprise cloud, regional, specialty media)
- **[`providers/local.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/providers/local.ts)** – Self-hosted models (e.g., `ollama-local`, `lm-studio`)
- **[`providers/search.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/providers/search.ts)** – Search-only services (e.g., `perplexity-search`, `brave-search`)
- **[`providers/audio.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/providers/audio.ts)** – Audio-specific services (e.g., `deepgram`, `elevenlabs`)
- **[`providers/upstream-proxy.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/providers/upstream-proxy.ts)** – Proxy providers (e.g., `cliproxyapi`)
- **[`providers/cloud-agent.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/providers/cloud-agent.ts)** – Cloud-agent implementations (e.g., `jules`, `devin`)
- **[`providers/system.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/providers/system.ts)** – System-level pseudo-providers (e.g., `auto`)

Each catalog exports a record mapping provider identifiers to rich `AiProviderDefinition` objects containing name, authentication method, icon, and capabilities.

## The Executor Pattern Architecture

When requests reach the Next.js API layer at [`src/app/api/v1/chat/completions/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/chat/completions/route.ts), the system delegates execution through a **Factory plus Strategy** pattern that abstracts provider-specific HTTP logic behind a common interface.

### Factory-Based Executor Selection

The factory function `getExecutor` in [`open-sse/executors/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/index.ts) maps provider identifiers to concrete executor classes:

```typescript
export function getExecutor(providerId: string): BaseExecutor {
  switch (providerId) {
    case "cursor":          return new CursorExecutor();
    case "codex":           return new CodexExecutor();
    case "antigravity":     return new AntigravityExecutor();
    // …specialized cases…
    default:                return new DefaultExecutor();
  }
}

```

The factory enables provider-specific optimizations while maintaining a consistent execution interface. Most of the 237 providers use the `DefaultExecutor` fallback, which implements generic OpenAI-compatible behavior.

### The BaseExecutor Strategy

The abstract `BaseExecutor` class in [`open-sse/executors/base.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/base.ts) defines the contract for all provider interactions. It encapsulates:

- **URL construction** via `buildUrl()`
- **Header generation** via `buildHeaders()`
- **Payload transformation** via `transformRequest()`
- **Retry logic** with exponential back-off
- **Abort signal** handling and cleanup
- **HTTP execution** via `fetch()` with typed responses

Provider-specific executors extend this base and override only the methods that differ from the standard OpenAI format. For example, `CursorExecutor` and `VertexExecutor` customize URL shapes and authentication headers while inheriting common retry and streaming logic.

### Provider-Specific Implementations

Specialized executors live alongside [`default.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/default.ts) in the `open-sse/executors/` directory. These subclasses handle edge cases:

- **`CursorExecutor`** – Custom authentication flows for Cursor IDE integration
- **`CodexExecutor`** – Specific payload formats for OpenAI Codex
- **`VertexExecutor`** – Google Cloud Platform URL construction and header signing

This Strategy pattern ensures that adding a new provider requires minimal code—often just a registry entry and occasionally a thin executor subclass.

## Implementation Examples

### Looking Up Provider Definitions

To access provider metadata anywhere in the application:

```typescript
import { AI_PROVIDERS } from "@/shared/constants/providers";

const providerId = "openai";
const def = AI_PROVIDERS[providerId];

console.log(def?.name);        // → "OpenAI"
console.log(def?.authMethod); // → "apiKey"

```

The proxy lazily resolves the identifier against the appropriate catalog module.

### Executing Provider Requests

The request handling flow demonstrates the factory pattern in action:

```typescript
import { getExecutor } from "@/open-sse/executors";

async function callProvider(req) {
  const providerId = req.provider;           // e.g., "anthropic"
  const exec = getExecutor(providerId);      // Factory instantiation
  const resp = await exec.execute(req.body); // BaseExecutor logic
  return resp;
}

```

This abstraction allows the chat core handler to remain agnostic to provider-specific HTTP details.

### Creating Custom Executors

For providers requiring non-standard endpoints, extend `DefaultExecutor`:

```typescript
import { DefaultExecutor } from "./default";

export class VertexExecutor extends DefaultExecutor {
  protected buildUrl() {
    return `https://us-central1-aiplatform.googleapis.com/v1/${this.model}:predict`;
  }

  protected buildHeaders() {
    return {
      Authorization: `Bearer ${this.apiKey}`,
      "Content-Type": "application/json",
    };
  }
}

```

Register the executor in [`open-sse/executors/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/index.ts) to integrate it into the routing logic.

## Summary

- **Centralized Registry**: OmniRoute consolidates 237 provider definitions in [`src/shared/constants/providers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/providers.ts) using a lazy-loading Proxy that defers catalog initialization.
- **Modular Catalogs**: Providers organize into authentication-based modules (OAuth, API key, local, etc.), ensuring single-responsibility for each catalog file.
- **Factory Pattern**: The `getExecutor()` function in [`open-sse/executors/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/index.ts) instantiates the correct executor class based on provider ID.
- **Strategy Implementation**: The `BaseExecutor` abstract class defines common retry, streaming, and error-handling logic, while concrete subclasses implement provider-specific URL and header construction.
- **Extensibility**: New providers require only registry entry in the appropriate catalog and optionally a custom executor class if not OpenAI-compatible.

## Frequently Asked Questions

### How does OmniRoute handle authentication differences between providers?

The registry categorizes providers by authentication method in separate catalog files ([`oauth.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/oauth.ts), `apikey`, [`web-cookie.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/web-cookie.ts), etc.). Each executor implementation then handles the specific authentication flow—whether Bearer tokens, cookie headers, or OAuth signatures—within its `buildHeaders()` method, keeping authentication logic encapsulated per provider.

### What happens if a provider ID is not found in the registry?

When accessing `AI_PROVIDERS[id]` for an unknown identifier, the Proxy's `get` handler returns `undefined` after checking all ten catalogs. Downstream code should validate the existence of the definition before attempting to instantiate an executor, typically throwing a 404 or validation error if the provider is not supported.

### How do I add a new provider to OmniRoute?

Adding a provider requires three steps: First, add the provider definition to the appropriate catalog module in `src/shared/constants/providers/` (e.g., [`providers/apikey/frontier-labs.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/providers/apikey/frontier-labs.ts) for API-key providers). Second, if the provider is not OpenAI-compatible, create a new executor class extending `BaseExecutor` or `DefaultExecutor` in `open-sse/executors/`. Third, register the provider ID in the `getExecutor` factory switch statement in [`open-sse/executors/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/index.ts).

### Why use a Proxy instead of a static object for the provider registry?

The Proxy pattern enables **lazy loading** of provider catalogs. Rather than importing and initializing all 237 provider definitions at module load time—which would increase startup memory and parse time—the Proxy defers catalog access until the first time a specific provider is referenced. This architectural choice optimizes for applications that only utilize a subset of available providers while maintaining the developer experience of a simple object lookup (`AI_PROVIDERS[id]`).