# How OmniRoute Manages Provider-Specific HTTP Dispatch: A Deep Dive into the Executor Architecture

> Explore OmniRoute's executor architecture for provider-specific HTTP dispatch. Learn how it centralizes LLM calls, builds custom requests, and dispatches efficiently.

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

---

**OmniRoute centralizes all HTTP calls to LLM providers through a lazy-loaded executor system that resolves provider-specific classes to build custom URLs, authentication headers, and request bodies before dispatching the final HTTP request.**

OmniRoute is an open-source routing layer that standardizes communication with diverse LLM backends. The system handles **provider-specific HTTP dispatch** through a centralized executor architecture, ensuring that each request reaches the correct endpoint with properly formatted authentication and payload structure. This approach allows the router to support everything from OpenAI-compatible APIs to specialized providers like Anthropic, Azure AI, and local self-hosted models without hardcoding provider logic into the main request handlers.

## The Executor Architecture: Centralizing HTTP Dispatch

At the heart of OmniRoute's dispatch system lies the **executor registry**, implemented in [`open-sse/executors/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/index.ts). When a chat completion request enters the system through [`open-sse/handlers/chatCore.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/handlers/chatCore.ts), it calls `getExecutor(provider)` to resolve the appropriate handler for the target provider.

The registry uses lazy loading via `loadRegisteredExecutor` (defined in [`open-sse/executors/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/registry.ts)) to instantiate specialized classes only when needed. If no specific executor exists for a provider, the system falls back to `DefaultExecutor`, a shared implementation in [`open-sse/executors/default.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/default.ts) that handles the majority of OpenAI-compatible providers while remaining extensible for custom configurations.

This architecture creates a **plug-and-play** system where adding support for a new provider requires only registering a new executor class or extending the default implementation with provider-specific overrides.

## The Five-Step Provider Dispatch Process

Each HTTP request follows a strict transformation pipeline within the executor. The process ensures that provider quirks—such as custom authentication schemes, unique URL patterns, and model-specific parameters—are handled consistently.

### Step 1: Resolving the Executor via getExecutor()

The dispatch begins when `getExecutor(providerId)` is invoked in [`open-sse/executors/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/index.ts). This function checks the registry for a pre-registered executor matching the provider identifier. If found, it loads the specialized class (such as `ClaudeWebExecutor` or `BedrockExecutor`). If no match exists, it instantiates a `DefaultExecutor` with the provider's configuration from [`open-sse/config/providerRegistry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/config/providerRegistry.ts).

### Step 2: Building Provider-Specific URLs with buildUrl()

Once resolved, the executor constructs the target endpoint through `buildUrl(model, stream, …)`, defined in [`open-sse/executors/default.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/default.ts) at line 28. This method selects the correct API path based on the provider type and model capabilities:

- **OpenAI-compatible providers**: Switch between `/chat/completions` and `/responses` based on the model's API requirements
- **Gemini**: Constructs model-specific paths like `<model>:generateContent` or the SSE streaming variant
- **Poe**: Routes to `chat`, `responses`, or Claude-specific `messages` endpoints depending on the target format
- **Local models**: Falls back to `localDefault` URLs from the provider catalog when no explicit base URL is configured

### Step 3: Assembling Authentication Headers via buildHeaders()

The `buildHeaders` method (line 72 in [`open-sse/executors/default.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/default.ts)) constructs the authentication layer. It merges operator-provided custom headers with protocol-specific requirements:

- **Anthropic providers**: Injects `x-api-key` and optional `Authorization` headers for non-official gateways, plus version compatibility headers for Claude code support
- **Azure AI**: Forces `api-key` header transmission and respects connection-level flags for Responses API enforcement
- **OpenAI-compatible**: Standard `Authorization: Bearer` token handling
- **Gigachat**: Prepares headers for token refresh workflows managed by [`open-sse/services/tokenRefresh.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/tokenRefresh.ts)

### Step 4: Normalizing Request Bodies with transformRequest()

Before dispatch, `transformRequest` (line 86 in [`open-sse/executors/default.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/default.ts)) sanitizes and normalizes the payload. This step applies provider-specific defaults such as JSON-schema fallbacks, stream-options injection, tool name length limits, and strips unsupported parameters that would cause upstream errors. Each executor can override this method to implement model-specific payload transformations.

### Step 5: Executing the HTTP Call

Finally, the executor's `execute` method forwards the constructed request. The default implementation delegates to `executeWithSessionPool` (found later in [`open-sse/executors/default.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/default.ts)), which manages connection pooling, retries, and concurrency gating. Specialized executors may inject additional logic here, such as Nvidia-specific concurrency limits or Gigachat token refresh cycles.

## Provider-Specific Implementation Patterns

Different LLM backends require distinct handling strategies. OmniRoute encodes these variations within specialized executors or configuration-driven defaults.

### OpenAI-Compatible and Azure AI Providers

For OpenAI-compatible endpoints, the `DefaultExecutor` honors custom `baseUrl` and `chatPath` configurations from the provider registry. Azure AI receives special treatment through forced `api-key` headers and connection flags that determine whether to use the standard chat completions or the newer Responses API format.

### Anthropic and Poe Integrations

Anthropic-compatible providers use `x-api-key` authentication with optional `Authorization` fallbacks for third-party gateways. The executor automatically injects Anthropic-version headers to ensure compatibility with Claude Code tooling. Poe executors dynamically select endpoints based on the target model's native format, routing to OpenAI-style chat endpoints, Response API endpoints, or native Claude `messages` endpoints as needed.

### Gemini and Local Model Handling

Google Gemini models require URL patterns that embed the model name directly in the path (e.g., `models/gemini-pro:generateContent`). Local and self-hosted models bypass remote authentication entirely, falling back to catalog-defined `localDefault` endpoints when no explicit URL configuration exists.

## Implementation Example: Dispatching a Request

The following TypeScript example demonstrates the complete dispatch flow using OmniRoute's executor system:

```typescript
import { getExecutor } from "./open-sse/executors/index.ts";

async function chat(providerId: string, model: string, body: any) {
  // 1️⃣ Resolve the executor for the chosen provider
  const executor = await getExecutor(providerId);

  // 2️⃣ Prepare credentials (normally supplied by the auth layer)
  const credentials = {
    accessToken: "user-token",
    providerSpecificData: { baseUrl: "https://api.custom.com/v1" },
  };

  // 3️⃣ Transform the request (URL, headers, body)
  const url = executor.buildUrl(model, true);
  const headers = executor.buildHeaders(credentials, true, undefined, model);
  const transformedBody = executor.transformRequest(model, body, true, credentials);

  // 4️⃣ Execute the HTTP call (the executor abstracts the fetch logic)
  const response = await executor.execute({
    url,
    method: "POST",
    headers,
    body: JSON.stringify(transformedBody),
    credentials,
  });

  return response;
}

// Example usage
chat("claude-web", "claude-3-5-sonnet-20240620", { messages: [{ role: "user", content: "Hello" }] })
  .then(console.log)
  .catch(console.error);

```

This implementation showcases how callers interact with a unified interface while the executor handles every **provider-specific HTTP dispatch** nuance internally.

## Summary

- **Executor Registry**: OmniRoute uses `getExecutor()` in [`open-sse/executors/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/index.ts) to lazily load specialized executors or fall back to `DefaultExecutor` for generic providers.
- **URL Construction**: The `buildUrl()` method handles provider-specific endpoint patterns, including OpenAI's dual API modes, Gemini's model-embedded paths, and local model fallbacks.
- **Authentication Abstraction**: `buildHeaders()` manages diverse auth schemes from Anthropic's `x-api-key` to Azure's `api-key` requirements.
- **Payload Normalization**: `transformRequest()` sanitizes requests to prevent upstream errors by stripping unsupported parameters and injecting required defaults.
- **Extensibility**: New providers require only a new executor registration or extension of `DefaultExecutor`, creating a true plug-and-play architecture for LLM routing.

## Frequently Asked Questions

### What is the role of DefaultExecutor in OmniRoute?

`DefaultExecutor` is the fallback implementation in [`open-sse/executors/default.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/default.ts) that handles HTTP dispatch for providers without specialized executors. It contains the core logic for `buildUrl()`, `buildHeaders()`, and `transformRequest()`, making it suitable for standard OpenAI-compatible APIs while remaining extensible through configuration overrides for custom providers.

### How does OmniRoute handle authentication for different providers?

Authentication is handled within each executor's `buildHeaders()` method. The system detects the provider type and injects the correct headers—such as `Authorization: Bearer` for OpenAI, `x-api-key` for Anthropic, or `api-key` for Azure AI—while merging operator-provided custom headers. Token refresh for providers like Gigachat is managed centrally through [`open-sse/services/tokenRefresh.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/tokenRefresh.ts).

### Can OmniRoute support custom or self-hosted LLM providers?

Yes. Self-hosted and local models are supported through the `DefaultExecutor` using `localDefault` URL configurations from the provider catalog. If a provider requires unique authentication or payload handling, developers can register a custom executor in [`open-sse/executors/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/registry.ts) without modifying the core routing logic.

### Where does the executor resolution happen in the request lifecycle?

Executor resolution occurs at the entry point of the chat completion handler in [`open-sse/handlers/chatCore.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/handlers/chatCore.ts). This early resolution ensures that provider-specific logic—including URL building, header assembly, and body transformation—occurs before any HTTP connection is established, allowing the system to fail fast on configuration errors rather than during network transmission.