# How OmniRoute Translates Between Different LLM Provider Formats: A Deep Dive into the Translator Architecture

> Discover how OmniRoute translates LLM provider formats using its hub-and-spoke architecture. Normalize requests and convert responses seamlessly.

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

---

**OmniRoute uses a hub-and-spoke translator layer that normalizes all inbound requests to an OpenAI-style canonical schema and converts outbound responses back to the target provider's native format.**

OmniRoute is an open-source LLM routing framework that abstracts away provider-specific API differences through a unified translation system. This article examines how the project handles format conversion between providers like OpenAI, Gemini, and Claude—enabling developers to route requests across multiple backends without rewriting client code.

## The Core Translator Hub: `translateRequest` and `translateResponse`

All format conversion in OmniRoute flows through two central functions defined in [`open-sse/translator/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/index.ts). The **translator hub** acts as a single integration point that delegates to provider-specific modules based on source-to-target mappings.

### Request Translation (Line 306)

The `translateRequest()` function initiates every outbound translation:

```ts
export function translateRequest(
  sourceFormat: SourceFormat,
  targetFormat: TargetFormat,
  payload: unknown,
  state: RequestState,
  context: RequestContext
): Promise<TranslationResult>

```

This function performs three operations:

1. **Registry lookup** – Queries [`open-sse/translator/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/registry.ts) to find the appropriate request translator for the source → target pair
2. **Payload transformation** – Rewrites messages, function-call blocks, tool results, and token limits into the target format
3. **Credential mapping** – Returns `translationCredentials` for the downstream executor

### Response Translation (Line 794)

The `translateResponse()` function handles inbound translation after provider execution:

```ts
export function translateResponse(
  targetFormat: TargetFormat,
  sourceFormat: SourceFormat,
  payload: unknown,
  state: TranslationState
): unknown

```

This normalizes streaming chunks or complete responses back to the OpenAI-compatible format expected by clients and downstream OmniRoute features like tool-call handling and SSE processing.

## The Translator Registry: Mapping Format Pairs

The registry system in [`open-sse/translator/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/registry.ts) maintains the mapping between supported format combinations. It enables dynamic discovery of available translation pathways without hardcoding provider logic in the hub.

To inspect supported translations programmatically:

```ts
import { registry } from "@/translator/registry";

const supportedPairs = registry.getSupportedPairs();
// Returns: [["openai","gemini"], ["openai","claude"], ...]

```

The registry pattern keeps the core hub agnostic to specific providers—new translators can be added without modifying [`index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/index.ts).

## Provider-Specific Translator Modules

Individual translators live in dedicated files following a naming convention: `{source}-to-{target}.ts` for requests, `{source}-to-{target}.ts` for responses.

### OpenAI to Gemini Request Translation

File: [`open-sse/translator/request/openai-to-gemini.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/request/openai-to-gemini.ts)

This module handles critical conversions including:

- **Message role mapping** – OpenAI's `system`/`user`/`assistant`/`tool` roles to Gemini's `user`/`model` structure
- **Function calling** – Rewriting OpenAI function definitions to Gemini's `tools` declaration format
- **Token parameters** – Mapping `max_tokens` to Gemini's `maxOutputTokens`
- **Multimodal content** – Converting image URLs to Gemini's inline data format

### Gemini to OpenAI Response Translation

File: [`open-sse/translator/response/gemini-to-openai.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/response/gemini-to-openai.ts)

This module normalizes:

- **Streaming chunks** – Gemini's `delta` structure to OpenAI's `choices[0].delta` format
- **Finish reasons** – Mapping `STOP`, `MAX_TOKENS`, `SAFETY` to OpenAI equivalents
- **Tool call outputs** – Converting Gemini's `functionCall` blocks to OpenAI's `tool_calls` array
- **Candidate handling** – Flattening Gemini's multi-candidate responses to single-choice format

## Format Definitions and Type Safety

The [`open-sse/translator/formats.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/formats.ts) file enumerates all supported format identifiers:

```ts
export type SourceFormat = "openai" | "gemini" | "claude" | "antigravity";
export type TargetFormat = "openai" | "gemini" | "claude" | "antigravity";

```

These type definitions ensure compile-time safety across the translation pipeline and provide a single source of truth for available integrations.

## Shared Helper Utilities

The `open-sse/translator/helpers/` directory contains reusable logic that keeps individual translators small:

| Helper | Purpose |
|--------|---------|
| [`maxTokensHelper.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/maxTokensHelper.ts) | Normalizes token budget calculations across providers with different limit semantics |
| [`toolCallShim.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/toolCallShim.ts) | Creates compatibility layers for function calling schemas that don't map 1:1 |
| [`imageSizeMapper.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/imageSizeMapper.ts) | Handles dimension constraints and encoding requirements for multimodal inputs |
| [`schemaCoercion.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/schemaCoercion.ts) | Validates and coerces parameter types where provider schemas diverge |

## End-to-End Translation Flow

Here's how the complete translation pipeline executes for a cross-provider request:

```ts
import { translateRequest } from "@/translator";
import { getExecutor } from "@/executors";

// Client sends OpenAI-format request
const openAiPayload = {
  model: "gpt-4o-mini",
  messages: [{ role: "user", content: "What's the weather in Paris?" }],
  temperature: 0.7,
};

// Step 1: Translate to target provider format
const { model, result, stream, translationCredentials } = await translateRequest(
  "openai",      // source format
  "gemini",      // target format
  openAiPayload,
  {} as any,     // request state
  {} as any,     // request context
);

// Step 2: Execute against provider
const executor = getExecutor("gemini");
const rawResponse = await executor.execute({
  model,
  body: result,
  stream,
  credentials: translationCredentials,
});

```

For streaming responses, translation happens per-chunk:

```ts
import { translateResponse } from "@/translator";

function onProviderChunk(chunk: unknown, state: TranslationState) {
  // Step 3: Normalize back to OpenAI format
  const openAiChunk = translateResponse(
    "openai",    // target format (what client expects)
    "gemini",    // source format (what provider sent)
    chunk,
    state,       // tracks multi-chunk state like tool call accumulation
  );
  
  sendToClient(openAiChunk);
}

```

## Why This Architecture Matters

The **hub-and-spoke translator design** provides three critical benefits:

1. **Schema uniformity** – Downstream OmniRoute features (circuit breakers, combo routing, memory, skills) operate on a single well-known OpenAI-compatible schema regardless of upstream provider
2. **Extensibility** – Adding a new provider requires only implementing two translator modules (request + response) and registering the format pair
3. **Testability** – Each translator is a pure function that can be unit tested in isolation without mocking external APIs

Because translation happens at the network boundary, the rest of the codebase remains provider-agnostic—enabling features like automatic failover between Gemini and Claude without format-aware logic in the routing layer.

## Summary

- OmniRoute's **translator hub** in [`open-sse/translator/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/index.ts) exposes `translateRequest()` (line 306) and `translateResponse()` (line 794) as the primary API for format conversion
- The **registry system** in [`open-sse/translator/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/registry.ts) maps source-to-target format pairs to concrete translator implementations
- **Provider-specific translators** like [`openai-to-gemini.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/openai-to-gemini.ts) and [`gemini-to-openai.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/gemini-to-openai.ts) handle the actual payload transformation
- **Format definitions** in [`formats.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/formats.ts) provide type safety and a canonical enumeration of supported integrations
- **Helper utilities** in `open-sse/translator/helpers/` extract reusable logic for token budgets, tool calls, and multimodal content
- The architecture implements a **hub-and-spoke pattern** that guarantees downstream components see only OpenAI-compatible schemas

## Frequently Asked Questions

### What LLM providers does OmniRoute support for translation?

OmniRoute currently supports translation between **OpenAI**, **Gemini**, **Claude**, and **Antigravity** formats as defined in [`open-sse/translator/formats.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/formats.ts). The registry pattern allows new providers to be added by implementing request and response translator modules without modifying the core hub.

### How does OmniRoute handle streaming responses from non-OpenAI providers?

Streaming translation uses `translateResponse()` called per-chunk with a `TranslationState` object that persists across chunks. This state tracks partial tool calls, accumulated content, and finish reasons—enabling accurate reconstruction of OpenAI-compatible streaming deltas even when the source provider uses different framing or multi-candidate structures.

### Can I use OmniRoute's translator layer independently of the routing features?

Yes. The translator modules are designed as **pure functions** with no dependencies on OmniRoute's circuit breakers, combo routing, or memory systems. You can import `translateRequest` and `translateResponse` directly from `@/translator` to convert payloads without executing through OmniRoute's executor pipeline.

### Where are the actual HTTP calls to providers made?

HTTP execution happens in **provider-specific executors** under `open-sse/executors/`, not in the translator layer. Translators only handle payload transformation—the executor receives the translated body and handles authentication, transport, and retry logic. This separation keeps translation logic stateless and testable.