# How OmniRoute Handles Structured Output Conversion Across LLM Provider Formats

> Learn how OmniRoute streamlines LLM structured output conversion across provider formats using its pluggable translator layer and Format Registry.

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

---

**OmniRoute uses a pluggable translator layer with a central Format Registry to convert requests and responses between incompatible LLM provider schemas while preserving structured outputs like tool calls, thinking signatures, and JSON schemas.**

OmniRoute is an open-source routing layer that normalizes interactions between diverse LLM providers. The project's **structured output conversion** system ensures that complex payloads—including tool definitions, reasoning budgets, and response formats—remain intact when translating between OpenAI, Gemini, Claude, and other providers.

## The Format Registry: Mapping Source to Target

At the heart of OmniRoute's conversion system is a central registry located in [`open-sse/translator/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/registry.ts). This module maintains a bidirectional map that pairs source formats with target formats, registering both request and optional response translators for each combination.

The registry exposes two key lookup functions: `getRequestTranslator` and `getResponseTranslator` (lines 35‑42). When registering a new translation path, developers provide the source format, target format, request translator function, and an optional response translator function. For example, mapping OpenAI to Gemini uses `openaiToGeminiRequest` for the request side while passing `null` for the response side when no custom conversion is needed.

This design creates a systematic pipeline where any provider format can be supported by implementing the translation interface and registering the pair, enabling OmniRoute to handle heterogeneous API schemas through a unified abstraction.

## Request Translation Pipeline

Request translators act as transformers that receive the original model name, raw body payload, stream flag, and credential object, then produce a provider-specific payload. The implementation in [`open-sse/translator/request/openai-to-gemini.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/request/openai-to-gemini.ts) demonstrates how complex structured data is preserved during conversion.

### Generation Config and Reasoning Budgets

The OpenAI-to-Gemini translator maps standard generation parameters between schemas. Lines 188‑207 handle the conversion of temperature, top-p, top-k, and stop tokens into Gemini's `generationConfig` structure.

For advanced reasoning features, the translator maps OpenAI's `reasoning_effort` parameter to Gemini's `thinkingConfig` (lines 224‑252). This ensures that structured thinking budgets and reasoning controls survive the translation process, allowing users to specify reasoning intensity regardless of the target provider's native terminology.

### Tool Call Conversion

Tool definitions require significant schema reshaping. Lines 368‑467 in [`open-sse/translator/request/openai-to-gemini.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/request/openai-to-gemini.ts) convert OpenAI's `tools` array into Gemini's `functionCall` parts, handling the nesting structure differences between the providers. The translator manages the `tool_choice` parameter, converting OpenAI's `"auto"` or specific tool selections into Gemini's equivalent enabling modes.

### Response Format Handling

When clients specify structured output requirements using OpenAI's `response_format` parameter, the translator maps these to Gemini's `responseMimeType` and `responseSchema` fields (lines 992‑1012). This preserves JSON schema constraints and MIME type specifications, ensuring that providers enforce the same structured output contracts even when the request originated from a different API format.

## Response Translation and Streaming

After the upstream provider processes a request, OmniRoute may need to reshape the response back into the client's expected format. This occurs through registered response translators that handle both complete payloads and streaming Server-Sent Events (SSE).

### Reusing Projectors Across Providers

Not every source-target pair requires unique response translation logic. The OpenAI-to-Gemini path reuses the generic Antigravity projector defined in [`open-sse/translator/response/openai-to-antigravity.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/response/openai-to-antigravity.ts) because Gemini and Antigravity share compatible response envelopes. This registration occurs in [`open-sse/translator/response/openai-to-gemini.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/response/openai-to-gemini.ts) (lines 14‑15), demonstrating how the registry supports composition and code reuse across similar provider formats.

### Claude-Specific Response Mapping

When converting OpenAI streams to Claude format, OmniRoute employs a dedicated response mapper in [`open-sse/translator/response/openai-to-claude.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/response/openai-to-claude.ts). This translator handles the conversion of OpenAI's delta-based streaming chunks into Claude's `content_block_*` structures, manages XML-based tool invocations, and maps finish reasons between the two schemas. The implementation accounts for Claude's specific event types and tool use representations that differ significantly from OpenAI's streaming protocol.

## Tool Name and Signature Preservation

Translators maintain a `toolNameMap` to reconcile provider-specific naming conventions, particularly when tool identifiers contain characters allowed by one provider but restricted by another. The [`open-sse/translator/helpers/geminiToolsSanitizer.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/helpers/geminiToolsSanitizer.ts) module sanitizes tool names and maintains bidirectional rename mappings to ensure round-trip consistency.

For advanced Gemini features, the system supports `signaturelessToolCallMode` and `supportsSignatureBypass` flags, allowing thought signatures to be embedded or bypassed depending on the target model's capabilities. These utilities in [`open-sse/translator/helpers/geminiHelper.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/helpers/geminiHelper.ts) handle content conversion, safety settings, and JSON schema cleaning to ensure that structured tool outputs remain valid across provider boundaries.

## Execution Flow

When an API route receives a request, OmniRoute determines the **source format** (e.g., `FORMATS.OPENAI`) through request inspection. It then looks up the appropriate **target format** based on the selected provider and invokes the registered request translator from [`open-sse/translator/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/registry.ts). After the upstream request completes, the response or SSE stream passes through the matching response translator before returning to the client.

This execution model ensures that **structured output conversion** happens transparently at the edge, allowing client applications to use a single API format while routing to multiple backend providers without losing fidelity in tool definitions, reasoning parameters, or response schemas.

```typescript
// Resolve a request translator for OpenAI → Gemini
import { getRequestTranslator } from '@/open-sse/translator/registry';
import { FORMATS } from '@/open-sse/translator/formats';

const translate = getRequestTranslator(FORMATS.OPENAI, FORMATS.GEMINI);
if (!translate) throw new Error('No translator registered');

// Example OpenAI payload
const openaiBody = {
  model: 'gpt-4o',
  messages: [{ role: 'user', content: 'What is the weather?' }],
  temperature: 0.7,
  tool_choice: 'auto',
  tools: [{ type: 'function', function: { name: 'get_weather', parameters: {} } }],
};

// Convert to Gemini format (ready for provider dispatch)
const geminiRequest = translate('gpt-4o', openaiBody, false, null);
console.log(geminiRequest);

```

```typescript
// Convert an OpenAI streaming chunk to Claude format
import { getResponseTranslator } from '@/open-sse/translator/registry';

const toClaude = getResponseTranslator(FORMATS.OPENAI, FORMATS.CLAUDE);
if (!toClaude) throw new Error('Missing response translator');

// Simulated OpenAI chunk (normally received from SSE)
const openaiChunk = {
  id: 'chatcmpl-123',
  model: 'gpt-4o',
  choices: [{ delta: { content: 'Hello' }, finish_reason: 'stop' }],
};

const claudeMessages = toClaude(openaiChunk, {}); // state object managed across chunks
console.log(claudeMessages);

```

## Summary

- OmniRoute implements **structured output conversion** through a centralized Format Registry in [`open-sse/translator/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/registry.ts) that maps source and target provider pairs to specific translator functions.
- Request translators in [`open-sse/translator/request/openai-to-gemini.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/request/openai-to-gemini.ts) handle complex mappings including generation configs (lines 188‑207), reasoning budgets (lines 224‑252), tool calls (lines 368‑467), and response formats (lines 992‑1012).
- Response translators normalize streaming chunks and completion payloads back to the client's expected schema, with some paths like OpenAI → Gemini reusing Antigravity projectors while others like OpenAI → Claude require dedicated mappers in [`open-sse/translator/response/openai-to-claude.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/response/openai-to-claude.ts).
- Tool name sanitization and signature handling occur through helper modules including [`geminiToolsSanitizer.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/geminiToolsSanitizer.ts) and [`geminiHelper.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/geminiHelper.ts), maintaining mapping integrity across provider-specific constraints.
- The pluggable architecture allows new provider formats to be supported by registering translation functions without modifying core routing logic.

## Frequently Asked Questions

### How does OmniRoute register new provider format translators?

Developers register translators by calling the `register` function in [`open-sse/translator/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/registry.ts) with the source format, target format, request translator function, and optional response translator. This creates a lookup entry that the routing layer queries at runtime via `getRequestTranslator` and `getResponseTranslator` to resolve the appropriate conversion logic for any provider pair.

### What happens to OpenAI's `response_format` when converting to Gemini?

The translator maps OpenAI's `response_format` parameter to Gemini's `responseMimeType` and `responseSchema` fields (lines 992‑1012 in [`open-sse/translator/request/openai-to-gemini.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/request/openai-to-gemini.ts)). This ensures JSON schema constraints and MIME type specifications are preserved, allowing Gemini to enforce the same structured output contracts that were requested in the OpenAI format.

### Why does the OpenAI to Gemini conversion reuse the Antigravity response translator?

The OpenAI-to-Gemini path registers `null` for custom response translation and instead uses the Antigravity projector because Gemini and Antigravity share compatible response envelope structures. This design pattern, visible in [`open-sse/translator/response/openai-to-gemini.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/response/openai-to-gemini.ts) (lines 14‑15), reduces code duplication by allowing similar provider formats to share translation logic through the registry's composition model.

### How does OmniRoute handle tool name incompatibilities between providers?

Translators maintain a `toolNameMap` to track bidirectional rename mappings between provider-specific naming conventions. The [`geminiToolsSanitizer.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/geminiToolsSanitizer.ts) helper sanitizes tool names to satisfy Gemini's character restrictions while preserving the original identifiers for round-trip consistency, ensuring that tool calls invoked in one format can be correctly matched and executed in the target provider's ecosystem.