# @standardagents/openrouter

OpenRouter provider package for Standard Agents - access multiple LLM providers through a unified gateway

> **Info:**
>
> For direct access, set `OPENROUTER_API_KEY` in your environment. Standard Agents Builder can use hosted routing through `STANDARD_AGENTS_API_KEY` when the provider key is absent. Hosted access depends on platform configuration.

## Overview

The `@standardagents/openrouter` package provides the OpenRouter provider factory for Standard Agents. OpenRouter is a multi-provider gateway that routes requests to various LLM providers (OpenAI, Anthropic, Google, Meta, and more) through a single API.

- Key Features

  - Access to models from multiple providers
  - Automatic pricing data fetched from OpenRouter API
  - Typed `providerOptions` for routing configuration
  - Provider selection, fallbacks, and price limits
  - Zero Data Retention (ZDR) endpoints
  - Provider-executed OpenRouter server tools

## Installation

```bash npm
npm install @standardagents/openrouter
```

```bash pnpm
pnpm add @standardagents/openrouter
```

```bash yarn
yarn add @standardagents/openrouter
```

## Quick Start

```typescript agents/models/conversational.ts
import { defineModel } from '@standardagents/spec';
import { openrouter } from '@standardagents/openrouter';

export default defineModel({
  name: 'conversational',
  provider: openrouter,
  model: 'google/gemma-4-31b-it',
});
```

> **Note:**
>
> OpenRouter models automatically fetch pricing from the OpenRouter API. You do not need to specify `inputPrice` or `outputPrice`.

## Provider Factory

The `openrouter` export is a provider factory function:

```typescript
import { openrouter } from '@standardagents/openrouter';

defineModel({
  name: 'my-model',
  provider: openrouter,  // Pass the factory, not a string
  model: 'google/gemma-4-31b-it',
});
```

## Model ID Format

OpenRouter uses a `provider/model-name` format for model IDs:

| Model developer | Example Model ID                    |
| --------------- | ----------------------------------- |
| Google          | `google/gemma-4-31b-it`             |
| NVIDIA          | `nvidia/nemotron-3-ultra-550b-a55b` |
| Z.ai            | `z-ai/glm-4.7-flash`                |
| MiniMax         | `minimax/minimax-m3`                |
| Moonshot AI     | `moonshotai/kimi-k3`                |
| Tencent         | `tencent/hy3`                       |

Browse all available models at [openrouter.ai/models](https://openrouter.ai/models).

## Provider Options

The `openrouter` factory includes a typed schema for routing configuration:

```typescript
import { defineModel } from '@standardagents/spec';
import { openrouter } from '@standardagents/openrouter';

export default defineModel({
  name: 'secure-chat',
  provider: openrouter,
  model: 'google/gemma-4-31b-it',
  providerOptions: {
    provider: {
      zdr: true,  // Zero Data Retention
      only: ['deepinfra'],  // Only route to DeepInfra
      max_price: {
        prompt: 5,  // Max $5 per million input tokens
        completion: 25,  // Max $25 per million output tokens
      },
    },
  },
});
```

### Routing Options

All routing options are nested under the `provider` key:

| Option                     | Type                | Description                                            |
| -------------------------- | ------------------- | ------------------------------------------------------ |
| `order`                    | `string[]`          | Provider slugs to try in order                         |
| `allow_fallbacks`          | `boolean`           | Allow fallback to other providers (default: true)      |
| `require_parameters`       | `boolean`           | Only use providers that support all request parameters |
| `data_collection`          | `'allow' \| 'deny'` | Control data storage policies                          |
| `zdr`                      | `boolean`           | Restrict to Zero Data Retention endpoints              |
| `only`                     | `string[]`          | Restrict to these providers only                       |
| `ignore`                   | `string[]`          | Skip these providers                                   |
| `sort`                     | `string \| object`  | Sort by price, throughput, or latency                  |
| `max_price`                | `object`            | Maximum price constraints                              |
| `quantizations`            | `string[]`          | Allowed quantization levels                            |
| `preferred_min_throughput` | `number \| object`  | Minimum throughput preference                          |
| `preferred_max_latency`    | `number \| object`  | Maximum latency preference                             |

### Server Tool Options

OpenRouter server tools are provider-executed tools. Enable the tool names with
`providerTools`, select them from prompts like normal tools, and pass optional
OpenRouter parameters through `providerOptions.serverTools`:

```typescript
export default defineModel({
  name: 'openrouter-research',
  provider: openrouter,
  model: 'nvidia/nemotron-3-ultra-550b-a55b',
  providerTools: ['web_search', 'web_fetch', 'datetime', 'image_generation'],
  providerOptions: {
    serverTools: {
      web_search: { max_results: 5 },
      web_fetch: { max_content_tokens: 50000 },
      datetime: { timezone: 'America/New_York' },
      image_generation: { quality: 'high' },
    },
  },
});
```

`serverTools` configures native OpenRouter tool parameters only. It is stripped
from the request body after the provider converts selected tools into
`openrouter:*` tool definitions.

### Price Limits

Set hard limits on pricing (request fails if no provider meets threshold):

```typescript
providerOptions: {
  provider: {
    max_price: {
      prompt: 1,        // Max $1 per million input tokens
      completion: 5,    // Max $5 per million output tokens
      request: 0.01,    // Max $0.01 per request
      image: 0.05,      // Max $0.05 per image
    },
  },
}
```

### Provider Selection

Control which providers handle your requests:

```typescript
// Only use specific providers
providerOptions: {
  provider: {
    only: ['deepinfra', 'novita'],
  },
}

// Prefer certain providers in order
providerOptions: {
  provider: {
    order: ['deepinfra', 'novita'],
    allow_fallbacks: true,
  },
}

// Exclude specific providers
providerOptions: {
  provider: {
    ignore: ['chutes'],
  },
}
```

### Sorting

Sort available providers by different criteria:

```typescript
// Sort by price (cheapest first)
providerOptions: {
  provider: {
    sort: 'price',
  },
}

// Sort by throughput (fastest first)
providerOptions: {
  provider: {
    sort: 'throughput',
  },
}

// Advanced sorting with partition
providerOptions: {
  provider: {
    sort: {
      by: 'latency',
      partition: 'model',
    },
  },
}
```

### Zero Data Retention (ZDR)

For sensitive data, restrict to ZDR endpoints:

```typescript
providerOptions: {
  provider: {
    zdr: true,  // Only use providers with Zero Data Retention
  },
}
```

### Performance Preferences

Set soft preferences for throughput and latency:

```typescript
providerOptions: {
  provider: {
    // Simple: apply to p50 percentile
    preferred_min_throughput: 100,  // 100 tokens/sec minimum
    preferred_max_latency: 1,       // 1 second max latency

  },
}
```

Use objects to set percentile thresholds:

```typescript
providerOptions: {
  provider: {
    preferred_min_throughput: {
      p50: 100,
      p90: 50,
    },
    preferred_max_latency: {
      p50: 0.5,
      p99: 2,
    },
  },
}
```

## Type Safety

The `providerOptions` type is automatically inferred:

```typescript
import { openrouter } from '@standardagents/openrouter';
import type { OpenRouterProviderOptions } from '@standardagents/openrouter';

const options: OpenRouterProviderOptions = {
  provider: {
    zdr: true,
    only: ['deepinfra'],
    // zdr: 'yes',  // Error: expected a boolean
  },
};
```

## Model Capabilities

Set capabilities for proper framework behavior:

```typescript
export default defineModel({
  name: 'conversational',
  provider: openrouter,
  model: 'google/gemma-4-31b-it',
  capabilities: {
    supportsImages: true,
    supportsToolCalls: true,
    supportsStreaming: true,
    maxContextTokens: 262144,
  },
});
```

## Environment Setup

Set your OpenRouter API key:

```bash .dev.vars
OPENROUTER_API_KEY=sk-or-...
```

For a deployed project, set `OPENROUTER_API_KEY` in your project's environment settings on the Standard Agents platform.

## Example Configurations

### Budget-Conscious Model

```typescript
import { defineModel } from '@standardagents/spec';
import { openrouter } from '@standardagents/openrouter';

export default defineModel({
  name: 'budget-llm',
  provider: openrouter,
  model: 'z-ai/glm-4.7-flash',
  providerOptions: {
    provider: {
      sort: 'price',
      max_price: {
        prompt: 0.5,
        completion: 1,
      },
    },
  },
});
```

### High-Security Configuration

```typescript
export default defineModel({
  name: 'secure-chat',
  provider: openrouter,
  model: 'google/gemma-4-31b-it',
  providerOptions: {
    provider: {
      zdr: true,
      only: ['deepinfra'],
      data_collection: 'deny',
    },
  },
  capabilities: {
    supportsImages: true,
    supportsToolCalls: true,
    maxContextTokens: 262144,
  },
});
```

### Multi-Provider Fallback

```typescript
export default defineModel({
  name: 'resilient-model',
  provider: openrouter,
  model: 'google/gemma-4-31b-it',
  providerOptions: {
    provider: {
      order: ['deepinfra', 'novita'],
      allow_fallbacks: true,
    },
  },
});
```

### Performance-Optimized

```typescript
export default defineModel({
  name: 'fast-model',
  provider: openrouter,
  model: 'google/gemma-4-31b-it',
  providerOptions: {
    provider: {
      sort: 'throughput',
      preferred_min_throughput: 100,
      preferred_max_latency: 0.5,
    },
  },
});
```

## Tool Calling

OpenRouter tool calls are sent with strict function schemas. The provider normalizes object schemas for OpenAI-backed endpoints by listing every object property in `required`, while Standard Agents Builder still validates the returned tool arguments against the original tool Zod schema before execution.

When tools are present, `tool_choice: "auto"` is omitted because OpenRouter treats that as the default. This keeps endpoints that support tools but do not advertise the separate `tool_choice` parameter eligible for routing.

### Provider-Executed Server Tools

The OpenRouter provider exposes these built-in server tools through `getTools()`:

| Tool               | Native OpenRouter type        | Description                               |
| ------------------ | ----------------------------- | ----------------------------------------- |
| `web_search`       | `openrouter:web_search`       | Search the web server-side                |
| `web_fetch`        | `openrouter:web_fetch`        | Fetch and extract URL content server-side |
| `datetime`         | `openrouter:datetime`         | Resolve current date/time server-side     |
| `image_generation` | `openrouter:image_generation` | Generate images server-side               |

Standard Agents Builder marks these tools as provider-executed. The OpenRouter provider
translates them to native `openrouter:*` tools for both Chat Completions and
Responses requests, and records completed server tool usage through the generic
provider-tool log path.

### Responses API

Set `providerOptions.useResponsesApi` to `true` to select the Responses API.
This mode supports tool-call history and image inputs.
Generation settings apply to streaming and non-streaming requests.
`inspectRequest()` shows the serialized API fields.
Opaque provider options retain their wire field names.
Responses preserve canonical `reasoningDetails` across turns.
Builder also normalizes stored legacy summary and encrypted detail names before replay.
Encrypted details use the `data` field.
Each replayed reasoning item retains its provider ID.
A token-limit truncation reports the `length` finish reason.
Partial image events retain their generated bytes.
Tool-call arguments remain objects.
Invalid JSON argument values use an empty object.

## Generation Metadata

Stream finish chunks carry a response ID for metadata lookups.
The provider keeps credentials in its configuration.
SDK request timeouts produce retryable provider errors.
Rate-limit errors retain the SDK response's `Retry-After` value in seconds.

OpenRouter provides additional metadata about request routing that can be fetched after completion:

```typescript
import { fetchGenerationMetadata } from '@standardagents/openrouter';

const metadata = await fetchGenerationMetadata(apiKey, generationId);
// Returns: provider used, tokens, latency, etc.
```

`totalCost` is `null` when OpenRouter reports no cost for the generation.
Standard Agents runs this lookup after requests that use your own `OPENROUTER_API_KEY`.
Requests routed through the Standard Agents platform skip it: their logs show the price the router charged.

## Exports

```typescript
import {
  // Provider factory
  openrouter,

  // Provider options schema (Zod)
  openrouterProviderOptions,

  // Provider class (advanced usage)
  OpenRouterProvider,

  // Metadata utilities
  fetchGenerationMetadata,

  // Shared lab icon utilities
  getLabIconDataUri,
  getModelIconDataUri,
} from '@standardagents/openrouter';

import type {
  // TypeScript types
  OpenRouterProviderOptions,
  OpenRouterConfig,
  GenerationMetadata,
} from '@standardagents/openrouter';
```

## Next Steps

- [Models](/docs/core-concepts/models)

  Learn about model configuration

* [OpenAI Provider](/docs/providers/openai)

  Direct OpenAI API access

- [Prompts](/docs/core-concepts/prompts)

  Configure prompts with models

* [defineModel API](/docs/api-reference/define/model)

  Complete API reference
