# `LLMDB.Sources.OpenRouter`
[🔗](https://github.com/agentjido/llm_db/blob/main/lib/llm_db/sources/openrouter.ex#L1)

Remote source for OpenRouter metadata (https://openrouter.ai/api/v1/models?output_modalities=all).

- `pull/1` fetches data via Req and caches locally
- `load/1` reads from cached file (no network call)

## Options

- `:url` - API endpoint (default: "https://openrouter.ai/api/v1/models")
- `:req_opts` - Additional Req options for testing (e.g., `[plug: test_plug]`)
- `:api_key` - OpenRouter API key (optional for public model list)

## Configuration

Cache directory can be configured in application config:

    config :llm_db,
      openrouter_cache_dir: "priv/llm_db/upstream"

Default: `"priv/llm_db/upstream"`

## Usage

    # Pull remote data and cache
    mix llm_db.pull

    # Load from cache
    {:ok, data} = OpenRouter.load(%{})

# `transform`

Transforms OpenRouter JSON format to canonical Zoi format.

## Input Format (OpenRouter)

```json
{
  "data": [
    {
      "id": "openai/gpt-4",
      "name": "GPT-4",
      "context_length": 128000,
      "pricing": {
        "prompt": "0.00003",
        "completion": "0.00006"
      },
      "architecture": {
        "modality": "text->text",
        "tokenizer": "GPT",
        "instruct_type": "chatml"
      },
      "top_provider": {
        "max_completion_tokens": 16384
      },
      ...
    }
  ]
}
```

## Output Format (Canonical Zoi)

```elixir
%{
  "openrouter" => %{
    id: :openrouter,
    name: "OpenRouter",
    models: [
      %{
        id: "openai/gpt-4",
        provider: :openrouter,
        name: "GPT-4",
        limits: %{context: 128000, output: 16384},
        cost: %{input: 0.03, output: 0.06},
        pricing: %{
          components: [
            %{
              id: "tool.web_search",
              kind: "tool",
              tool: "web_search",
              unit: "call",
              per: 1,
              rate: 0.01
            }
          ]
        },
        ...
      },
      %{
        id: "perplexity/sonar-pro",
        provider: :openrouter,
        name: "Perplexity: Sonar Pro",
        ...
      }
    ]
  }
}
```

Main transformations:
- Keep model IDs exactly as provided by OpenRouter (e.g., `perplexity/sonar-pro`)
- All models registered under `:openrouter` provider only
- Transform pricing strings to floats (per 1M tokens)
- Map context_length → limits.context
- Map top_provider.max_completion_tokens → limits.output
- Extract modality information

## Provider Separation

OpenRouter models are distinct from native provider models. For example:
- `openrouter:perplexity/sonar-pro` - accessed via OpenRouter API
- `perplexity:sonar-pro` - accessed via native Perplexity API (from Perplexity source)

These are separate entries with potentially different pricing, limits, and capabilities.
Model IDs may contain `/` which is part of the ID string, not a provider delimiter.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
