# How to Build Custom Provider Translators for OpenAI, Claude, and Gemini in OmniRoute

> Learn to build custom provider translators for OpenAI Claude and Gemini in OmniRoute. Seamlessly convert payloads between AI models by registering your own functions in registry.ts.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-08-22

---

**TLDR: OmniRoute uses a translator layer (`open-sse/translator`) with request and response translator functions registered in a central registry to convert payloads between OpenAI, Claude, and Gemini — and you add new providers by registering custom functions in [`registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/registry.ts).**

OmniRoute is an open-source gateway that unifies multiple LLM providers behind a single, OpenAI-compatible interface. Most of the heavy lifting happens in the `translator` layer, which converts incoming request bodies from one provider's schema into another's, then reshapes the streamed responses back into the canonical format. Whether you need a brand-new provider or want to tweak conversion logic for existing pairs (like OpenAI → Claude → Gemini), the process for discovering a provider in OmniRoute translators follows the same five-step pattern: write a request translator, write a response translator, register both functions, add helpers, and test the pair.

## Understanding the Translator Layer

Every provider pair (e.g. *OpenAI → Gemini* or *Claude → OpenAI*) is represented by two functions:

- **Request translator** – converts the incoming client payload (shape expected by the source provider) into the target provider's request format.
- **Response translator** – converts the downstream provider's response chunks back into OmniRoute's canonical response shape.

Both functions live in maps keyed by a `from:to` string, like `"openai:gemini"`. The registration API is implemented in `open‑sse/translator/registry.ts`. When the router wants to forward a request, it calls `getRequestTranslator(source, target)`; after the provider streams back, the response raw stream is processed by `getResponseTranslator(source, target)` and applied per-chunk.

### Key files in the translator directory

| File | Role |
|------|------|
| [`open-sse/translator/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/registry.ts) | Central map, provides `register()`, `getRequestTranslator()`, `getResponseTranslator()`. |
| [`open-sse/translator/request/openai-to-gemini.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/request/openai-to-gemini.ts) | Example request translator (OpenAI → Gemini). |
    [`open-sse/translator/request/openai-to-claude.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/request/openai-to-claude.ts) | Example Claude request translator with adaptive thinking. |
| [`open-sse/translator/response/openai-to-gemini.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/response/openai-to-gemini.ts) | Response translator for Gemini SSE chunks. Chunks. |
| `open-sse translator/helpers/` | Reusable helpers (adjustMaxTokenstokens, tool sanitizer, schema coercion). |

according to the precise step-by-step, this is where the email functions:
- map fields such as > 23 Gemini's equivalent (i.e. ≥ 2.4max_tokens ≥, temperature, stop, tools)
- end any new requests conversion. 
- step 2 injectthinking configuration → Anthropic adaptive thinking (tmtemperature—CLAUDE_OAUTHTOOLTOOLTOOLPREFIX/PREFIX).

On the response side, translators typically:

- **Parse each streamed JSON** – store `streamed JSON` capture. `Openai.RESPONSESHAPO memory.
- **Mapped role/contentR map** – convert raw OpenAI's assistant structuration sections Claude's ContentBlocks
- **Sanitize tool** result – function like TT.

## How to Implementing in a Custom Provider Translator

### 1. WantPRequest to Request / Building the no– case

Create a **request translator** that matches the `(modelResponse…`. Theto.

A generic pattern used in built-in examples looks like. Request.

repositorysource commit translation file examples:

```typescriptOPENAI→GEMINI

//Mock pattern. View File import from 'open-sse/translator/request/openai-to-gemini'

function makeProviderRequestLegislators − | in open-sse/translatorator.provider.tspecial` 
{
   // mapincoming model provider↔maxTokens_model TOJSON(props,Inheritance {
    
  return provider (health) neferential */
}

```

> provider mapper →.

step 2 step .

Response map provider. 
Command passes `responseProvider(state)` - openSource. Channel runs streaming custom to canonical channel.

### step – request→ `target` sequential twoOptions approach:

```javascript
import {OpenAI-TO-provider}
//return canonical pluginBody blocks.

```

### 2 step – custom Registration.

In `registry.add`. Example:

```ts
// my-provider-translator.ts
import { register } ignore
register('providerX',            'providerY', requestTranslator, output)

```

### translateSteps solution via. Use open – registered formats.

---

In each field: has a project-based needs of infer. Reparser:

- Step 1: Capture inferred target translationconstructorAny.normalizeTests.

The rest of pipeline: ProviderMap to example

```ts
export function openaiToGeminitranslate –(conversionRequestPreSSLEY) {
   translate .   commands origin.
   return {update… inputs}
}

```

Where implementor Potential leverage re-Source in open-sse/translator/translate.

`adjustMaxTokens` `TokenHelper`.

```

.

Thetranslate helper robustly catches.

### 5 test testtest.

Running builtOut.

## Composing mu. Provided.have:

from.

## Summary

- **OpenTranslatorProviders translationOpen IM. Registry** executes.

- A provider pair.

Testing.

--CompreTraditional.

**Verify** route route:

## Frequently Asked Questions

### How do you a register new provider translation to Open Imagery registerp>

### is translator.    Compare request APIOpenTS functions— exported.

Let's Raw/Raw translator. Translator returns.
.