How OmniRoute Handles Format Translation Between OpenAI, Claude, and Gemini API Specifications
OmniRoute normalizes requests and responses between the three major LLM providers by converting all incoming payloads to a unified internal schema called xAI Responses, then translating the provider's xAI Completed response back to the original caller's expected format.
OmniRoute is an open-source routing layer that abstracts away structural differences between LLM APIs. By implementing bidirectional format translation between OpenAI, Claude, and Gemini API specifications, the project enables developers to use a single integration point while maintaining compatibility with each provider's native SDKs. The translation logic resides in dedicated modules under src/lib/providers/xai/translators, ensuring that system messages, tool definitions, and multimodal inputs map correctly regardless of the source API.
The xAI Responses Internal Model
All translators map external payloads to a common internal representation defined in the xAI Responses schema. This normalized structure decouples the routing logic from provider-specific JSON shapes.
interface XaiResponsesRequest {
model?: string | null;
input: XaiInputItem[]; // ordered list of user/assistant/tool items
instructions?: string; // system-prompt or Gemini systemInstruction
tools?: XaiTool[]; // function-tool declarations
tool_choice?: string;
temperature?: number;
top_p?: number;
max_output_tokens?: number;
stop?: string[];
reasoning?: { effort: "low" | "medium" | "high" };
}
Conversely, an xAI Completed object contains an array of output items that the outbound translators convert back into provider-specific response formats. This bidirectional flow ensures that caching, resilience, and streaming layers operate on a single consistent data model.
OpenAI Translation Layer
The OpenAI translator bridges the Chat Completions API format and the internal xAI Responses schema. Source code is located at src/lib/providers/xai/translators/openai-chat.ts.
Inbound Conversion
The chatRequestToXaiResponses function parses OpenAI Chat requests and extracts:
- System messages → mapped to the
instructionsfield - User/assistant messages → converted to
inputcontent blocks (input_text,input_image, etc.) - Tool calls and results → normalized to
function_call/function_call_outputitems - Tools definitions → passed through unchanged via
toolsPassthrough
Outbound Conversion
The xaiCompletedToChatJson function builds an OpenAI-compatible ChatCompletion object from the xAI Completed response. It re-injects text content, tool calls, and optional refusal fields into the standard OpenAI response envelope.
Claude Translation Layer
The Anthropic translator handles the Messages API format, managing Claude-specific content blocks and tool schemas. Implementation is in src/lib/providers/xai/translators/claude.ts.
Inbound Conversion
The claudeRequestToXaiResponses function processes Anthropic payloads by:
- Mapping the
systemfield toinstructions - Converting the
messagesarray toinputitems with user/assistant content blocks - Transforming Anthropic
imageblocks intoinput_imageitems - Converting
tool_useandtool_resultblocks into separatefunction_call/function_call_outputentries - Translating tool definitions via
toolsAnthropicToXaito match the xAI function-tool shape
Outbound Conversion
The xaiCompletedToClaudeJson function reconstructs an Anthropic Messages JSON object. It populates the content array with output_text, refusal, and function_call blocks while preserving usage metadata required by Anthropic's SDK.
Gemini Translation Layer
The Google Gemini translator manages the generateContent API format, handling multimodal parts and function declarations. Code resides in src/lib/providers/xai/translators/gemini.ts.
Inbound Conversion
The geminiRequestToXaiResponses function processes Gemini requests by:
- Mapping
systemInstructionto theinstructionsfield - Converting each
contententry toinputitems, deriving roles from therolefield - Using
partsToXaiBlocksto transform Gemini parts (text,inlineData,fileData) intoinput_textorinput_imageblocks - Extracting embedded function calls and responses via
extractFunctionItems - Converting
functionDeclarationsto xAItoolsusingtoolsGeminiToXai
Outbound Conversion
The xaiCompletedToGeminiJson function generates a Gemini response by building a candidates array. It converts output_text to Gemini text parts and function_call entries to Gemini functionCall parts, while injecting usageMetadata for token accounting.
Request Lifecycle and Flow Overview
OmniRoute processes provider-specific requests through a standardized pipeline:
- API Route receives a request (e.g.,
/v1/chat/completions) and identifies the target provider - Translator Selection activates the appropriate module (
openai-chat.ts,claude.ts, orgemini.ts) - Normalization converts the incoming payload to an xAI Responses request
- Execution sends the normalized request to the downstream service
- Completion receives an xAI Completed object from the provider
- Denormalization maps the completed object back to the original provider's response format
- Streaming returns the formatted response to the caller via SSE or JSON
Because each translator adheres to the same internal contract, surrounding layers for caching, rate limiting, and error handling remain provider-agnostic.
Summary
- OmniRoute uses a unified xAI Responses schema to decouple routing logic from provider-specific formats
- Dedicated translators in
src/lib/providers/xai/translatorshandle bidirectional conversion for OpenAI, Claude, and Gemini - Inbound translators normalize system prompts, message histories, tools, and multimodal content to the internal model
- Outbound translators reconstruct provider-native response envelopes including usage metadata and content blocks
- The architecture allows the core executor to treat all requests uniformly while preserving compatibility with native SDKs
Frequently Asked Questions
How does OmniRoute handle tool function definitions across different API formats?
Each translator contains provider-specific logic for tool schema conversion. OpenAI tools pass through largely unchanged via toolsPassthrough, while Claude tools undergo transformation via toolsAnthropicToXai and Gemini tools convert via toolsGeminiToXai. The internal xAI representation uses a standardized function-tool shape that captures name, description, and parameters, ensuring that function calls and results map correctly regardless of the source API's JSON schema.
What happens to system messages and instructions during translation?
System-level instructions normalize to the instructions field in the xAI Responses model. For OpenAI, the translator extracts content from messages with role: "system". For Claude, it maps the top-level system field. For Gemini, it pulls from systemInstruction. During outbound translation, the system message returns to its provider-specific location, preserving the exact structure expected by each SDK.
Can OmniRoute handle image and multimodal inputs when translating between APIs?
Yes. The translators process multimodal content through specialized mapping functions. OpenAI image URLs and base64 data convert to input_image blocks. Claude's image blocks undergo similar transformation. Gemini's inlineData and fileData parts convert via partsToXaiBlocks. When generating responses, outbound translators reconstruct the appropriate provider-specific image formats, enabling seamless passthrough of visual content across all three APIs.
Why does OmniRoute use an intermediate xAI format instead of direct translation?
The xAI Responses schema acts as a least common denominator that simplifies the addition of new providers and features. By translating once to a unified model and once back to the target format, OmniRoute avoids combinatorial complexity (N×M translations) and ensures that caching, streaming, and error handling logic remains provider-agnostic. This architecture is validated by unit tests in tests/unit/xai-translators.test.ts that verify round-trip correctness for all supported providers.
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 →