How OmniRoute Executors Handle Upstream Requests: Base, Default, Cursor, Codex, and Vertex Explained
OmniRoute routes every LLM request through a hierarchy of executor classes—BaseExecutor, DefaultExecutor, CursorExecutor, CodexExecutor, and VertexExecutor—each overriding specific methods to build URLs, assemble headers, transform payloads, and manage retries for their respective providers.
Understanding how OmniRoute executors handle upstream requests is essential for troubleshooting provider-specific quirks or extending the router to new endpoints. The diegosouzapw/OmniRoute repository implements a strategy pattern where each executor inherits common transport logic from base.ts and selectively overrides behaviors to satisfy unique provider contracts—from OpenAI-compatible APIs to Google Vertex AI’s OAuth 2.0 requirements.
BaseExecutor: The Foundation
All executors inherit from BaseExecutor in open-sse/executors/base.ts. This class implements the generic lifecycle of an upstream request: URL resolution, header construction, payload transformation, retry logic, and credential refresh.
URL Resolution via buildUrl()
The buildUrl() method (lines 396–417) constructs the final endpoint. For OpenAI-compatible providers, it combines the custom base URL with an optional chat path. For other providers, it falls back to the static baseUrls array defined in the provider configuration.
// Conceptual flow inside BaseExecutor
protected buildUrl(config: ProviderConfig): string {
if (config.isOpenAICompatible) {
return `${config.baseUrl}${config.chatPath || '/v1/chat/completions'}`;
}
return config.baseUrls[0];
}
Header Construction Pipeline
Header generation occurs in two stages. First, buildHeadersPreamble() (lines 822–848) creates the baseline set including Content-Type, provider-specific headers, and an optional User-Agent from environment variables. It also resolves the effective API key, accounting for key rotation when multiple keys are configured.
Then, buildHeaders() (lines 1009–1031) finalizes the set by injecting the Authorization header, selecting the appropriate Accept header for streaming versus JSON responses, and normalizing Anthropic-specific header variations.
Request Transformation with transformRequest()
Before the fetch occurs, transformRequest() (lines 1033–1084) sanitizes the payload. It removes empty fields, fixes tool definitions, and strips provider-specific illegal keys. This ensures that downstream providers receive clean, valid JSON regardless of what the client originally sent.
Retry Logic and Credential Refresh
The shouldRetry() method (lines 1086–1090) implements circuit-breaker logic for rate limits. Using RETRY_CONFIG (max attempts = 2, delay = 2000 ms), it determines whether a 429 response should trigger a retry on the next URL in the provider’s fallback list.
For long-lived sessions, needsRefresh() (lines 1096–1115) checks the expiresAt timestamp against a provider-specific lead time. Subclasses override refreshCredentials() to silently obtain new tokens—critical for Vertex AI’s short-lived OAuth tokens.
DefaultExecutor: OpenAI-Compatible Providers
Located in open-sse/executors/default.ts, DefaultExecutor handles the majority of modern LLM APIs that follow the OpenAI specification (Anthropic-compatible endpoints, Groq, Mistral, etc.).
It inherits BaseExecutor wholesale and only overrides transformRequest() when the provider advertises a custom chatPath or requires specific body tweaks, such as explicitly adding the stream flag. If you are integrating a standard OpenAI-compatible provider, you are likely using this executor through the registry in open-sse/executors/index.ts.
CursorExecutor: Microsoft Cursor
The CursorExecutor in open-sse/executors/cursor.ts addresses Microsoft Cursor’s unique constraints:
- Custom Headers: Injects the mandatory
x-cursor-modelheader required by the Cursor service. - Payload Sanitization: Actively removes
prompt_cache_retentionfrom the request body (see the comment inBaseExecutor.transformRequestat lines 71–73) because Cursor rejects this field as unrecognized. - Path Injection: For legacy endpoints, it may embed the model identifier directly into the URL path rather than the request body.
CodexExecutor: GitHub Codex
GitHub Codex requires specific handling found in open-sse/executors/codex.ts:
- Tool Model Prefix Stripping: Calls
stripVersionedToolModelPrefix()(lines 5005–5016 inbase.ts) to remove date-suffixes from tool model identifiers that Codex cannot parse. - Authentication Variants: In addition to the standard “effective key” logic, it conditionally injects a
Codex-API-Keyheader if the provider configuration supplies one, supporting GitHub’s dual-key authentication schemes.
VertexExecutor: Google Vertex AI
Google Vertex AI diverges significantly from the standard HTTP JSON pattern, necessitating the VertexExecutor in open-sse/executors/vertex.ts:
- URL Construction: Overrides
buildUrl()to construct the Vertex-specific endpoint pattern:https://{location}-aiplatform.googleapis.com/v1/projects/{projectId}/locations/{location}/publishers/..., interpolatinglocationandprojectIdfrom the provider configuration. - OAuth 2.0 Headers: Uses
Authorization: Bearer <accessToken>rather than API keys, requiring the credential refresh logic inBaseExecutorto fetch new tokens via Google’s identity endpoints. - Body Wrapping: Wraps the standard chat payload in an
instancesarray and moves generation parameters to aparametersobject per Vertex’s REST contract.
How Requests Flow Through the System
When a client hits the OmniRoute API, the request traverses the following path:
- Route Entry:
src/app/api/v1/chat/completions/route.tsvalidates authentication and forwards the payload toopen-sse/handlers/chatCore.ts. - Executor Selection:
open-sse/executors/index.tsmaps the provider ID (e.g.,openai-compatible-…,cursor,codex,vertex) to the corresponding executor class. - Execution Orchestration: The executor’s
execute()method (inherited fromBaseExecutor) orchestrates the call:- Resolves base URL via
resolveBaseUrl()→buildUrl(). - Assembles headers via
buildHeadersPreamble()→buildHeaders(), triggering credential refresh ifneedsRefresh()returns true. - Sanitizes the body via
transformRequest(). - Performs the
fetchwith timeout, abort-signal merging, and retry loops governed byshouldRetry().
- Resolves base URL via
- Uniform Return: Returns a structured
ExecutorExecuteResultcontaining{ response, url, headers, transformedBody, transport }, allowing downstream services (MCP, A2A, streaming handlers) to process the response agnostically.
Code Examples
Standard OpenAI-Compatible Provider
import { getExecutor } from '@/open-sse/executors';
const exec = getExecutor('openai-compatible-groq', providerConfig);
const result = await exec.execute({
model: 'llama-3.1-70b',
stream: true,
body: { messages: [{ role: 'user', content: 'Hello' }] },
credentials: userCreds
});
Google Vertex AI Direct Usage
import { VertexExecutor } from '@/open-sse/executors/vertex';
const vertex = new VertexExecutor('vertex', vertexConfig);
const result = await vertex.execute({
model: 'gemini-1.5-pro',
stream: false,
body: {
instances: [{ content: 'Write a haiku' }],
parameters: { temperature: 0.7 }
},
credentials: vertexCreds
});
Cursor with Automatic Field Stripping
import { CursorExecutor } from '@/open-sse/executors/cursor';
const cursor = new CursorExecutor('cursor', cursorConfig);
// Note: `prompt_cache_retention` is automatically removed before sending upstream
const result = await cursor.execute({
model: 'cursor-fast',
stream: true,
body: {
prompt: 'Explain recursion',
prompt_cache_retention: true
},
credentials: cursorCreds
});
Summary
- BaseExecutor (
open-sse/executors/base.ts) provides the shared infrastructure for URL building, header assembly, request transformation, retry logic, and credential refresh that all providers inherit. - DefaultExecutor (
open-sse/executors/default.ts) serves OpenAI-compatible providers with minimal overrides, covering the majority of LLM endpoints. - CursorExecutor (
open-sse/executors/cursor.ts) adds thex-cursor-modelheader and stripsprompt_cache_retentionto satisfy Microsoft Cursor’s strict payload validation. - CodexExecutor (
open-sse/executors/codex.ts) normalizes tool model names and supports GitHub’s dual-key authentication pattern. - VertexExecutor (
open-sse/executors/vertex.ts) handles Google Vertex AI’s OAuth 2.0 token refresh, custom URL patterns withlocationandprojectId, and theinstances/parametersbody structure. - The executor registry in
open-sse/executors/index.tsmaps provider IDs to classes, enabling the system to route requests through the correct strategy without client-side configuration changes.
Frequently Asked Questions
What is the difference between BaseExecutor and DefaultExecutor?
BaseExecutor is an abstract foundation containing provider-agnostic logic for HTTP transport, retries, and authentication. DefaultExecutor is a concrete implementation for OpenAI-compatible APIs that largely relies on the base class, only overriding transformRequest() when specific providers require minor body tweaks. Most providers in OmniRoute use DefaultExecutor unless they require custom headers, URL patterns, or authentication schemes like Cursor, Codex, or Vertex.
How does OmniRoute handle authentication for Google Vertex AI?
The VertexExecutor overrides credential handling to support OAuth 2.0 access tokens rather than static API keys. It calls needsRefresh() to check token expiration against a lead time, then executes refreshCredentials() to fetch a new Bearer token from Google’s identity endpoints before injecting it into the Authorization header via buildHeaders().
Why does CursorExecutor remove the prompt_cache_retention field?
Microsoft Cursor’s API strictly validates incoming payloads and rejects unrecognized keys. Because prompt_cache_retention is a provider-specific extension used by other services but invalid for Cursor, the CursorExecutor (via inherited logic in BaseExecutor.transformRequest) strips this field before serialization to prevent 400 Bad Request errors.
How does retry logic work across all executors?
All executors inherit shouldRetry() from BaseExecutor, which checks HTTP status codes (specifically 429) against the RETRY_CONFIG constant (max 2 attempts, 2000ms delay). If a rate limit is hit, the executor automatically attempts the request against the next URL in the provider’s baseUrls array, transparent to the calling code.
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 →