# How to Use the Responses API Transformer in OmniRoute to Convert Between API Formats

> Master API format conversion with OmniRoute's Responses API Transformer. Learn to automatically translate payloads and transform responses efficiently using createResponsesApiTransformStream.

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

---

**To convert between API formats, pipe the Chat Completions SSE stream through `createResponsesApiTransformStream` in [`open-sse/transformer/responsesTransformer.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/transformer/responsesTransformer.ts), or use `handleResponsesCore` to automatically translate Requests API payloads and transform the response.**

The OmniRoute proxy supports both standard OpenAI Chat Completions and the newer Responses API streaming protocols. When you need to serve Responses API clients while connecting to providers that only support Chat Completions, the **Responses API transformer** bridges this gap by translating requests and transforming the streaming response format through a stateful pipeline.

## How the Responses API Transformer Works

The conversion process follows a specific pipeline that ensures streaming compatibility and accurate stateful event emission.

### Request Translation Phase

When a client sends a request in the Responses API shape, the `handleResponsesCore` function in [`open-sse/handlers/responsesHandler.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/handlers/responsesHandler.ts) receives the payload. This function translates the request body using `convertResponsesApiFormat` from [`open-sse/translator/helpers/responsesApiHelper.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/helpers/responsesApiHelper.ts) to match the native Chat Completions structure. The translation process automatically sets `stream = true` to ensure the upstream provider returns a Server-Sent Events (SSE) stream compatible with the transformation pipeline.

### Stream Transformation Phase

After dispatching the translated request via `handleChatCore`, the upstream Chat Completions SSE stream flows through `createResponsesApiTransformStream` located in [`open-sse/transformer/responsesTransformer.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/transformer/responsesTransformer.ts). This **TransformStream** parses each incoming chunk and emits corresponding Responses API events such as `response.output_item.added`, `response.output_text.delta`, and `response.function_call_arguments.delta`. A **keep-alive heartbeat** is then added to prevent client timeouts during long-running operations.

### State Management and Output Ordering

The transformer maintains a **state object** that buffers message text, function-call arguments, reasoning snippets, and an ordered list of emitted items called `completedOutputItems`. When the stream completes, the `buildDenseOutput` function sorts these items by `output_index` and emission sequence. This ensures the final `response.completed` event contains a stable, deterministic array ready for client consumption.

## Key Implementation Details

Understanding the internal mechanics helps troubleshoot edge cases and optimize performance:

- **State tracking**: The transformer holds buffers for partial content across multiple SSE chunks, including reasoning text and tool call arguments.
- **Deterministic output**: The `recordCompletedItem` function tracks each finished item, while `buildDenseOutput` ensures proper ordering in the final response array.
- **Reasoning handling**: Supports both native `reasoning_content` fields and textual `` tags, emitting them as `response.reasoning_summary_*` events before normal message content.
- **Tool-call streaming**: Transforms Chat Completions `tool_calls` into separate `response.output_item.added` and `response.function_call_arguments.delta` events, stripping empty strings for clean JSON payloads.
- **Keep-alive mechanism**: A periodic `: keepalive` SSE line prevents client timeouts, with automatic cleanup on stream cancellation.

## Code Examples

### Handling Responses API Requests End-to-End

Use the handler function to process full Requests API conversations:

```typescript
import { handleResponsesCore } from "@omniroute/open-sse/handlers/responsesHandler.ts";

await handleResponsesCore({
  body: {
    model: "gpt-4o",
    input: "Explain quantum computing",
    tools: [{ type: "code_interpreter" }]
  },
  modelInfo: { provider: "openai", model: "gpt-4o" },
  credentials: { apiKey: process.env.OPENAI_KEY },
  log: null,
  onCredentialsRefreshed: () => {},
  onRequestSuccess: () => console.log("Stream started"),
  onDisconnect: () => console.log("Client disconnected"),
  connectionId: "conn-123",
  signal: abortController.signal,
});

```

### Manual Stream Transformation

For custom pipelines or testing, apply the transformer directly to a Chat Completions SSE stream:

```typescript
import { createResponsesApiTransformStream } from "@omniroute/open-sse/transformer/responsesTransformer.ts";
import { createSseHeartbeatTransform, HEARTBEAT_SHAPES } from "@omniroute/open-sse/utils/heartbeat.ts";

const chatSseStream: ReadableStream = fetchChatCompletionsStream(); // Your upstream source
const transformed = chatSseStream
  .pipeThrough(createResponsesApiTransformStream())
  .pipeThrough(
    createSseHeartbeatTransform({
      signal: abortSignal,
      intervalMs: 3000,
      shape: HEARTBEAT_SHAPES.OPENAI_RESPONSES_IN_PROGRESS,
    })
  );

for await (const chunk of transformed) {
  console.log(new TextDecoder().decode(chunk));
}

```

### Understanding the Output Structure

When the stream completes, the transformer constructs a final response object:

```typescript
// Internal structure from responsesTransformer.ts
const response = {
  id: state.responseId,
  object: "response",
  created_at: state.created,
  status: "completed",
  output: buildDenseOutput(), // Sorted array of all items
  usage: state.usage, // Optional token statistics
};

```

## Source File Reference

Implementations reside in specific modules within the OmniRoute repository:

- [`open-sse/transformer/responsesTransformer.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/transformer/responsesTransformer.ts) — Core `TransformStream` implementation that maps Chat Completions SSE events to Responses API events.
- [`open-sse/handlers/responsesHandler.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/handlers/responsesHandler.ts) — Endpoint handler coordinating request translation, chat core invocation, and transformation.
- [`open-sse/translator/helpers/responsesApiHelper.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/helpers/responsesApiHelper.ts) — Helper utilities converting Responses API request bodies to Chat Completions format.

## Summary

- **OmniRoute** bridges Chat Completions and Responses API formats through a dedicated transformer pipeline.
- The **`handleResponsesCore`** function orchestrates translation and streaming, while **`createResponsesApiTransformStream`** handles the SSE conversion.
- **State tracking** ensures accurate representation of tool calls, reasoning, and message ordering in the final output.
- **Keep-alive heartbeats** prevent timeouts during long-running streaming operations.

## Frequently Asked Questions

### What is the difference between Chat Completions and Responses API formats?

The Chat Completions API streams delta updates to conversation content, while the Responses API emits discrete events like `response.output_item.added` and `response.output_text.delta`. OmniRoute's transformer converts the former into the latter by parsing deltas and reconstructing them as semantic output items with proper indexing.

### How does OmniRoute handle tool calls when converting API formats?

The transformer detects `tool_calls` from the Chat Completions stream and emits them as `response.output_item.added` events followed by `response.function_call_arguments.delta` chunks. Empty strings and arrays are automatically stripped to ensure valid JSON payloads in the transformed stream.

### What happens to reasoning content during the transformation?

Reasoning content is extracted from either the `reasoning_content` field or parsed from `` tags in the source stream. The transformer emits `response.reasoning_summary_*` events for reasoning items before processing normal message content, ensuring proper ordering in the final output array.

### How do I add keep-alive heartbeats to the transformed stream?

Pipe the transformed stream through `createSseHeartbeatTransform` imported from the OmniRoute utilities, specifying an interval (typically 3000ms) and the `OPENAI_RESPONSES_IN_PROGRESS` shape. This enqueues periodic `: keepalive` SSE lines that prevent client timeouts without interfering with the actual response data.