# OpenRouter Config Sections: The Two Meanings of "OpenRouter"

## The Confusion

A user sees "OpenRouter" in **two places** in the Dashboard and wonders why there are "two OpenRouter menus" — and whether their OpenRouter setup actually worked.

## The Answer: Two Separate Config Sections

### 1. `providers.openrouter:` — The Provider (Model Routing)

```yaml
providers:
  openrouter:
    base_url: https://openrouter.ai/api/v1
    api_key_env: OPENROUTER_API_KEY
```

**Purpose:** Defines OpenRouter as a route for sending model API calls. When you pick "OpenRouter" in the model picker dialog (Dashboard → MODELS → CHANGE), Hermes uses this provider config to connect to OpenRouter's API.

**Where it shows in the Dashboard:**
- MODELS page → CHANGE button → "SET MAIN MODEL" dialog → "OpenRouter openrouter · N models" button
- The N models come from the **model catalog** (`model_catalog.enabled: true` fetches
  `https://hermes-agent.nousresearch.com/docs/api/model-catalog.json` which includes OpenRouter's
  available models)

**Activation:** The model picker lists ALL providers from `providers:` in config.yaml that have a corresponding API key set. If `OPENROUTER_API_KEY` is in `.env`, you'll see OpenRouter as a selectable provider.

---

### 2. Top-level `openrouter:` — Feature Configuration (Response Caching)

```yaml
openrouter:
  response_cache: true
  response_cache_ttl: 300
  min_coding_score: 0.65
```

**Purpose:** Configures OpenRouter-specific **features** — response caching (saves cost on repeated
  prompts) and the Pareto Code router's minimum coding score threshold. These are NOT about routing
  or which models you can use — they control OpenRouter API behaviors.

**Where it shows in the Dashboard:**
- CONFIG page → filter sidebar → "Openrouter 3" section (shows the 3 fields below)
- Clicking that filter reveals `openrouter.response_cache`, `openrouter.response_cache_ttl`,
  `openrouter.min_coding_score`

**Activation:** This section is built-in from Hermes Agent's default config. It's always present
  even if you don't have OpenRouter set up as a provider.

---

## Why Both Exist

| Section | Belongs to | Purpose | Shows in Dashboard |
|---------|-----------|---------|-------------------|
| `providers.openrouter:` | Provider routing | "Where to send model calls" | Model picker (MODELS → CHANGE) |
| Top-level `openrouter:` | Feature config | "How OpenRouter API behaves" | Config page filter "Openrouter 3" |

One is a **route** (where to send requests), the other is **behavioral settings** (caching, routing knobs). Hermes keeps them separate because:
- You could use OpenRouter as a provider but disable response caching
- You could configure caching defaults without having OpenRouter as an active provider (preparing for future use)

---

## Typical QA Diagnosis

If a user says "I see OpenRouter but I can't use it" or "I don't see the OpenRouter I set up":

1. **Check `.env`:** `grep OPENROUTER_API_KEY ~/.hermes/.env` — key must be uncommented and valid
2. **Check `providers:` in config.yaml:** Must have `openrouter:` with `base_url` and `api_key_env`
3. **Check model catalog is working:** `model_catalog.enabled: true` — the catalog fetches OpenRouter's model list
4. **Check the model picker:** Dashboard → MODELS → CHANGE → "OpenRouter openrouter · N models" should appear
5. **Switch to OpenRouter:** Click OpenRouter in the picker, select a model, click SWITCH. Or use `/model openrouter/<model>` in chat.

---

## Adding Models Missing from the Catalog

The curated model catalog only includes ~33 OpenRouter models. If a specific model doesn't appear in the picker:

### Quick Check

Fetch the catalog and search for the model:

```bash
curl -s https://hermes-agent.nousresearch.com/docs/api/model-catalog.json | \
  python3 -c "import json,sys; models=json.load(sys.stdin)['providers']['openrouter']['models']; \
  print([m['id'] for m in models if 'your-model-name' in m['id'].lower()])"
```

### Add Models to the Cache (Immediate Fix)

Edit `~/.hermes/cache/model_catalog.json` and add the missing model entries to the `providers.openrouter.models` array:

```python
import json

with open('/path/to/.hermes/cache/model_catalog.json') as f:
    data = json.load(f)

models_to_add = [
    {"id": "qwen/qwen3-235b-a22b", "description": ""},
    {"id": "qwen/qwen3-coder:free", "description": "free"},
]

existing_ids = {m["id"] for m in data["providers"]["openrouter"]["models"]}
for m in models_to_add:
    if m["id"] not in existing_ids:
        data["providers"]["openrouter"]["models"].append(m)

with open('/path/to/.hermes/cache/model_catalog.json', 'w') as f:
    json.dump(data, f, indent=2)
```

This fix only lasts until the cache refreshes (24-hour TTL).

### Persistent Override (Survives Cache Refresh)

1. **Create a local override JSON file** with ALL OpenRouter models (existing + your additions):

```python
import json

with open('/path/to/.hermes/cache/model_catalog.json') as f:
    data = json.load(f)

# Add your missing models first, then:
override = {
    "version": 1,
    "updated_at": "2026-05-11T21:14:00Z",
    "metadata": {"source": "local-override"},
    "providers": {
        "openrouter": data["providers"]["openrouter"]
    }
}

with open('/path/to/.hermes/cache/openrouter_override.json', 'w') as f:
    json.dump(override, f, indent=2)
```

2. **Set config.yaml to use it:**

```yaml
model_catalog:
  enabled: true
  url: https://hermes-agent.nousresearch.com/docs/api/model-catalog.json
  ttl_hours: 24
  providers:
    openrouter:
      url: file:///path/to/.hermes/cache/openrouter_override.json
```

**How it works:** The override URL (`file://` protocol supported via Python's `urllib`) is fetched fresh on every `_get_provider_block()` call — no disk cache for overrides. As long as the local file exists, those models always appear in the picker.

**Pitfall:** The override replaces, not merges — it must include ALL OpenRouter models you want to see, not just the additions. The local file must be in the same format as the main catalog's `providers.<name>.` block.

**Critical verification pitfall — `get_catalog()` does NOT prove your OpenRouter override is active:** the per-provider override is applied by `_get_provider_block("openrouter")`, which is what the `/model` picker and `get_curated_openrouter_models()` use. If you verify with `get_catalog(force_refresh=True)`, you'll only see the base manifest / disk cache and may falsely conclude your override was ignored. To verify the actual picker-visible list, call `from hermes_cli.model_catalog import get_curated_openrouter_models` and inspect that output instead.
