# How OmniRoute Translates Request/Response Formats Between OpenAI, Claude, and Gemini

> Discover how OmniRoute seamlessly translates LLM request/response formats between OpenAI Claude and Gemini using its bidirectional translation layer. Simplify your multi-model integrations.

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

---

**OmniRoute normalizes LLM provider differences through a bidirectional translation layer in `open-sse/translator` that converts OpenAI-compatible requests into native Claude and Gemini schemas, then transforms provider responses back into OpenAI-formatted payloads.**

OmniRoute acts as a universal API gateway that bridges the gap between OpenAI’s ubiquitous Chat Completions format and the distinct request/response schemas used by Anthropic’s Claude and Google’s Gemini. The translation system resides in the `open-sse/translator` package, where provider-specific converters handle bidirectional transformations. Understanding how OmniRoute translates request/response formats between OpenAI, Claude, and Gemini reveals the architectural patterns that enable seamless multi-provider LLM integration.

## The Translation Registry Architecture

OmniRoute’s translation system centers on a registry pattern defined in [`open-sse/translator/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/registry.ts). This file maintains a mapping between source and target format pairs—such as OpenAI → Gemini or Claude → OpenAI—and their corresponding translator functions.

The registry exposes two primary operations:

1. **Registration** – Developers call `register(FORMATS.OPENAI, FORMATS.GEMINI, openaiToGeminiBase, null)` to associate a converter function with a specific direction.
2. **Lookup** – The runtime invokes `getTranslator(sourceFormat, targetFormat)` to retrieve the appropriate request or response converter.

When a request arrives at `src/app/api/v1beta/models/[...path]/route.ts`, the API route inspects the payload to detect the source format. If the body contains a Gemini-style `contents` array, the system marks the source as **Gemini**; otherwise it defaults to **OpenAI**. The route then retrieves the translator and executes the conversion pipeline.

## Request Translation Workflow

The request translation phase transforms incoming OpenAI-formatted payloads into provider-native structures before forwarding them to upstream LLMs.

### OpenAI to Gemini Conversion

The [`open-sse/translator/request/openai-to-gemini.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/request/openai-to-gemini.ts) module handles conversion to Google’s API format. This translator constructs a `GeminiRequest` object with several critical transformations:

- **Generation Configuration** – Maps OpenAI `max_tokens` and `temperature` to Gemini’s `generationConfig`, applying caps via `capMaxOutputTokens` and `capThinkingBudget` from [`modelCapabilities.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/modelCapabilities.ts).
- **Safety Settings** – Injects `DEFAULT_SAFETY_SETTINGS` while preserving caller-provided overrides via utilities in [`open-sse/translator/helpers/geminiHelper.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/helpers/geminiHelper.ts).
- **Tool Sanitization** – Renames tools using `sanitizeGeminiToolName` (with optional `GeminiToolNameOptions`) to comply with Gemini’s naming constraints, storing the original mappings in `_toolNameMap` for round-trip conversion.
- **System Instruction Handling** – Collates OpenAI `system` messages into Gemini’s `systemInstruction` field, merging with any existing `body.system` content.
- **Role Merging** – Executes `mergeConsecutiveSameRoleContents()` (lines 68-80) to collapse adjacent messages sharing the same role, as Gemini rejects consecutive identical roles.

### OpenAI to Claude Conversion

For Anthropic targets, [`open-sse/translator/request/openai-to-claude.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/request/openai-to-claude.ts) performs Anthropic-specific adaptations:

- **Thinking Budget Injection** – Adds Claude-specific `thinking` blocks when model capabilities indicate extended thinking mode.
- **Tool Prefixing** – Rewrites tool call names with `CLAUDE_OAUTH_TOOL_PREFIX` to satisfy Anthropic validation requirements.
- **Content Validation** – Strips empty text blocks that would cause Claude API rejections.
- **Token Management** – Adjusts `max_tokens` parameters to align with Anthropic’s limits versus OpenAI’s conventions.

## Response Stream Translation

After the upstream provider returns data, OmniRoute reverses the transformation to emit OpenAI-compatible JSON or Server-Sent Events (SSE).

### Gemini to OpenAI Response Translation

The [`open-sse/translator/response/gemini-to-openai.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/response/gemini-to-openai.ts) module processes Gemini’s `candidates` objects and streaming chunks:

- Parses Gemini streaming chunks to extract `candidates` and `content` parts.
- Reconstructs OpenAI-style `tool_calls` from Gemini function calls.
- Restores **thought signatures** using [`geminiThoughtSignatureStore.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/geminiThoughtSignatureStore.ts) to preserve chain-of-thought metadata within OpenAI’s message schema.
- Normalizes `finish_reason` mappings between Gemini’s `STOP`/`MAX_TOKENS` and OpenAI’s equivalent states.

### Claude to OpenAI Response Translation

For Anthropic responses, [`open-sse/translator/response/claude-to-openai.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/response/claude-to-openai.ts) maps Claude’s rich content blocks:

- Transforms Claude’s `content` array (containing `text` and `tool_use` blocks) into OpenAI’s `message` structure with `tool_calls`.
- Normalizes tool result IDs to ensure consistency between Claude’s UUID format and OpenAI’s string identifiers.
- Drops unsupported Anthropic-specific fields that lack OpenAI equivalents.

## Provider-Specific Transformation Details

### Tool Name Sanitization and Safety Settings

Gemini imposes strict constraints on tool names and content safety. The [`open-sse/translator/helpers/geminiToolsSanitizer.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/helpers/geminiToolsSanitizer.ts) module provides `sanitizeGeminiToolName` to replace invalid characters, while [`open-sse/translator/helpers/geminiHelper.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/helpers/geminiHelper.ts) manages `DEFAULT_SAFETY_SETTINGS` for content filtering categories like `HARM_CATEGORY_DANGEROUS_CONTENT`.

### Message Role Merging and System Instructions

Because Gemini requires alternating roles and collapses system prompts into a single `systemInstruction` field, the translator must preprocess message histories. The `mergeConsecutiveSameRoleContents()` function ensures compliance by concatenating adjacent user messages or assistant messages into single `parts` arrays within the `contents` envelope.

## Practical Implementation Examples

The following examples demonstrate how clients interact with OmniRoute while the translation layer handles provider-specific formatting automatically.

### Calling Gemini via OpenAI Format

```javascript
import fetch from "node-fetch";

const resp = await fetch("http://localhost:20128/v1/chat/completions", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    model: "gemini-1.5-flash",
    messages: [
      { role: "system", content: "You are a helpful assistant." },
      { role: "user", content: "Explain quantum entanglement in plain language." },
    ],
    tool_choice: "auto",
    safetySettings: [{ category: "HARM_CATEGORY_DANGEROUS_CONTENT", threshold: "BLOCK_ONLY_HIGH" }],
  }),
});

const data = await resp.json();
console.log(data);

```

OmniRoute detects the Gemini model identifier, invokes the OpenAI-to-Gemini translator, and returns an OpenAI-shaped response object.

### Streaming Gemini Responses

```javascript
const resp = await fetch("http://localhost:20128/v1/chat/completions?stream=true", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    model: "gemini-1.5-pro",
    messages: [{ role: "user", content: "Write a poem about sunrise." }],
    stream: true,
  }),
});

for await (const chunk of resp.body) {
  process.stdout.write(chunk);
}

```

The streaming pipeline routes Gemini `candidates` through [`openai-to-gemini-sse.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/openai-to-gemini-sse.ts), emitting OpenAI-compatible `delta` events while preserving thought signatures.

### Using Claude Tools via OmniRoute

```javascript
const resp = await fetch("http://localhost:20128/v1/chat/completions", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    model: "claude-3-opus-1.2",
    messages: [{ role: "user", content: "What is the weather in Paris?" }],
    tools: [{
      type: "function",
      function: {
        name: "get_weather",
        description: "Fetch weather",
        parameters: {
          type: "object",
          properties: { city: { type: "string" } },
          required: ["city"]
        }
      }
    }],
    tool_choice: "required",
  }),
});

const data = await resp.json();

```

Behind the scenes, [`openai-to-claude.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/openai-to-claude.ts) prefixes tool names and injects the required `thinking` block before forwarding to Anthropic’s API.

## Summary

- OmniRoute uses a **registry pattern** in [`open-sse/translator/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/registry.ts) to map bidirectional conversions between OpenAI, Claude, and Gemini formats.
- **Request translators** in `open-sse/translator/request/` handle provider-specific constraints like Gemini’s role merging, safety settings, and Claude’s thinking blocks.
- **Response translators** in `open-sse/translator/response/` normalize streaming chunks and tool calls back into OpenAI-compatible schemas.
- **Helper utilities** manage tool name sanitization, token capping, and thought signature preservation to ensure round-trip fidelity.
- The system operates transparently, allowing clients to use OpenAI’s API contract while communicating with any supported provider.

## Frequently Asked Questions

### How does OmniRoute detect which provider format to use?

OmniRoute inspects the incoming request body in `src/app/api/v1beta/models/[...path]/route.ts`. If the payload contains a Gemini-specific `contents` array, it marks the source format as Gemini; otherwise it defaults to OpenAI. The target format is determined by the model identifier specified in the request.

### Can OmniRoute handle streaming responses from all three providers?

Yes. The response translation layer processes Server-Sent Events (SSE) through provider-specific handlers like [`openai-to-gemini-sse.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/openai-to-gemini-sse.ts) and [`claude-to-openai.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/claude-to-openai.ts). These modules parse native streaming formats—such as Gemini’s `candidates` objects—and convert them into OpenAI-compatible `delta` chunks in real-time.

### What happens to tool calls when translating between formats?

Tool calls undergo bidirectional mapping. When sending to Gemini, `sanitizeGeminiToolName` ensures compliance with naming constraints while storing original names in `_toolNameMap`. For Claude, tool names receive the `CLAUDE_OAUTH_TOOL_PREFIX` prefix. On the return path, translators restore original tool identifiers and map provider-specific tool result formats back to OpenAI’s `tool_calls` structure.

### Does OmniRoute support Claude’s extended thinking mode?

Yes. The [`openai-to-claude.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/openai-to-claude.ts) translator checks model capabilities and injects the `thinking` block into requests when appropriate. For Gemini thought signatures, the system uses [`geminiThoughtSignatureStore.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/geminiThoughtSignatureStore.ts) to preserve reasoning metadata that can be re-injected into OpenAI-formatted responses.