# ResponsesGateway

A third-party Responses API gateway for the Codex harness: OpenRouter, Vercel AI Gateway, or Cloudflare.

`OpenAiBuilder.responses_gateway` takes a `ResponsesGateway`. The gateway sets the base URL and model ID prefix, and the client switches to HTTPS with full replay and no stored responses. Gateways serve `Model::Sol`, `Model::Luna`, and `Model::Astra`, as `serves` reports, and require API-key authentication.

```rust
use nanocode::codex::{auth::OpenAiAuth, transport::ResponsesGateway};
use nanocode::{Model, Nanocode, OpenAi};

// 1. Route the client through OpenRouter with an app title
let openai = OpenAi::builder(OpenAiAuth::api_key(std::env::var(
    "OPENROUTER_API_KEY",
)?))
.responses_gateway(ResponsesGateway::openrouter().app_title("my-app"))
.model(Model::Luna)
.build()?;

// 2. Install it as the Codex harness
let runtime = Nanocode::builder().openai(openai).build_async().await?;
```

## Signature

```rust
// At nanocode::codex::transport::ResponsesGateway
impl ResponsesGateway {
    pub fn openrouter() -> Self;
    pub fn vercel() -> Self;
    pub fn cloudflare(account_id: impl Into<String>) -> Self;
    pub fn cloudflare_gateway(
        account_id: impl Into<String>,
        gateway_id: impl Into<String>,
    ) -> Self;
}
```

## Constructors

| Constructor                                  | Base URL                                                                | Model ID prefix |
| -------------------------------------------- | ----------------------------------------------------------------------- | --------------- |
| `openrouter()`                               | `https://openrouter.ai/api/v1`                                          | `openai`        |
| `vercel()`                                   | `https://ai-gateway.vercel.sh/v1`                                       | `openai`        |
| `cloudflare(account_id)`                     | `https://api.cloudflare.com/client/v4/accounts/<account_id>/ai/v1`      | `openai`        |
| `cloudflare_gateway(account_id, gateway_id)` | `https://gateway.ai.cloudflare.com/v1/<account_id>/<gateway_id>/openai` | none            |

```rust
use nanocode::codex::transport::ResponsesGateway;

// The Cloudflare unified API, and a provider-native AI Gateway endpoint
let unified = ResponsesGateway::cloudflare(account_id.clone());
let native =
    ResponsesGateway::cloudflare_gateway(account_id, "my-gateway");
```

## Options

Each option applies to one provider. An option on another provider fails `OpenAiBuilder.build` with `OpenAiError::InvalidConfiguration`.

### app_title

* **Type:** `impl Into<String>`
* **Provider:** OpenRouter

Sends the `X-OpenRouter-Title` header, which names the app in OpenRouter.

```rust
// Names the app in OpenRouter rankings
let gateway = ResponsesGateway::openrouter().app_title("my-app");
```

### app_url

* **Type:** `impl Into<String>`
* **Provider:** OpenRouter

Sends the `HTTP-Referer` header.

```rust
// Links the app's site
let gateway =
    ResponsesGateway::openrouter().app_url("https://example.com");
```

### provider_routing

* **Type:** `serde_json::Value`
* **Provider:** OpenRouter or Vercel

Sends provider preferences: OpenRouter's `provider` object, or Vercel's `providerOptions.gateway`. The value must be a JSON object.

```rust
use serde_json::json;

// Asks OpenRouter to prefer one provider
let gateway = ResponsesGateway::openrouter()
    .provider_routing(json!({ "order": ["openai"] }));
```

### gateway_id

* **Type:** `impl Into<String>`
* **Provider:** Cloudflare unified API

Sends the `cf-aig-gateway-id` header, which selects an AI Gateway for the unified API.

```rust
// Logs requests in one AI Gateway
let gateway =
    ResponsesGateway::cloudflare(account_id).gateway_id("my-gateway");
```

### gateway_token

* **Type:** `impl Into<String>`
* **Provider:** Cloudflare AI Gateway

Sends `cf-aig-authorization: Bearer <token>` to an authenticated gateway. With `OpenAiAuth::gateway_managed()`, the gateway adds the OpenAI key.

```rust
use nanocode::codex::auth::OpenAiAuth;

// The gateway holds the OpenAI key
let gateway =
    ResponsesGateway::cloudflare_gateway(account_id, gateway_id)
        .gateway_token(token);
let openai = OpenAi::builder(OpenAiAuth::gateway_managed())
    .responses_gateway(gateway)
    .build()?;
```

### byok_alias

* **Type:** `impl Into<String>`
* **Provider:** Cloudflare AI Gateway

Sends the `cf-aig-byok-alias` header, which selects a stored provider key.

```rust
// Selects the stored key named production
let gateway =
    ResponsesGateway::cloudflare_gateway(account_id, gateway_id)
        .byok_alias("production");
```

### base_url

* **Type:** `impl Into<String>`

Replaces the base URL, for example with a local capture server. The URL must be an absolute `http` or `https` URL without credentials, a query, or a fragment.

```rust
// Sends requests to a local server
let gateway =
    ResponsesGateway::openrouter().base_url("http://127.0.0.1:8080/v1");
```

## Capabilities

| Gateway                | WebSocket | Stored responses                   |
| ---------------------- | --------- | ---------------------------------- |
| OpenRouter             | No        | No, its Responses API is stateless |
| Vercel                 | Yes       | Yes                                |
| Cloudflare unified API | No        | No, it replaces response IDs       |
| Cloudflare AI Gateway  | No        | Yes                                |

```rust
use nanocode::codex::transport::{ResponsesGateway, ResponsesTransport};

// Vercel is the only gateway that also accepts the WebSocket transport
let openai = OpenAi::builder(key)
    .responses_gateway(ResponsesGateway::vercel())
    .transport(ResponsesTransport::WebSocket)
    .build()?;
```

## Errors

### OpenAiError

`OpenAiBuilder.build` returns `OpenAiError::InvalidConfiguration` for an option on the wrong provider, a malformed base URL, an empty header value or token, a non-object `provider_routing`, or ChatGPT authentication.

```rust
use nanocode::codex::{OpenAiError, transport::ResponsesGateway};

// app_title applies to OpenRouter, so this build fails
let result = OpenAi::builder(key)
    .responses_gateway(ResponsesGateway::vercel().app_title("my-app"))
    .build();
if let Err(OpenAiError::InvalidConfiguration { detail }) = result {
    eprintln!("{detail}");
}
```
