fabro/docs/public/integrations/openrouter.mdx
Bryan Helmkamp 3e065b806b
Bump lithos-llm to 43a42ac and migrate catalogs to the codecs schema
Move the lithos-llm pin from 55add459 to 43a42ac28e9d9bcf40a91abc02be4f12ca274ebb,
and the three Pebble pins from a39f43e to 67c9f48, Pebble `main`, which pins
that same lithos-llm revision so Cargo holds one lithos-llm crate. lithos-llm
`main` (ca19fac) is one commit further; that commit touches only its nightly
workflow, so this pin stays on the revision Pebble unifies with.

The `openai`, `anthropic`, `gemini`, and `openai-compatible` features are
gone upstream; each expanded to `runtime`, which `bedrock` implies, so the
four names leave the fabro-llm feature list. Every other manifest already
names `runtime`.

The catalog schema now names one adapter and many codecs per provider.
`adapter` defaults to `http`, `codecs = [...]` replaces `codec` and defaults
to `["openai-chat"]`, and the loader rejects the old `codec` key and the four
protocol-named adapter ids. Every inline catalog in tests and docs moves to
the new shape: the `openai-compatible` + `openai-chat` pair is dropped as the
default, `adapter = "openai"` + `codec = "openai-responses"` becomes
`codecs = ["openai-responses"]`, and the one test that swaps in a custom
adapter id now adds the line instead of replacing one. The settings
reference, the API schema's `Provider.adapter` description, and the SDK page
describe the new fields; the three `docs/superpowers/plans/` files that show
the old shape are dated, unchecked historical plans and are left as they are.

The implied agent profile for an operator provider that declares none used
to read the removed protocol adapter ids; it now reads the provider's first
codec (Anthropic Messages and Gemini map to their harnesses, the `bedrock`
adapter to Anthropic, everything else to OpenAI), with a test for the codec
path.

Absorbing the rest of the range: OpenRouter and Fireworks now ship enabled,
so the two fabro-llm tests that used OpenRouter as the disabled fixture use
`bedrock-openai`, and the docs and comments that said the two ship disabled
are corrected. The built-in catalog grew past 100 enabled model rows
(Vercel, TypeSafe, and the enabled OpenRouter and Fireworks rosters), so the
pagination shape test walks `page[offset]` to the last page instead of
assuming one page fits.

`cargo update -p` on the four crates also re-resolved a few already-locked
edges to match the lithos-llm lockfile: `windows-sys` 0.61.2/0.60.2 ->
0.59.0 under dirs-sys, errno, nu-ansi-term, quinn-udp, rustix,
rustls-platform-verifier, tempfile, terminal_size, and winapi-util;
`windows-core` 0.61.2 -> 0.62.2 under iana-time-zone; `errno` 0.2.8 ->
0.3.14 under signal-hook-registry; and `indexmap` 2.13.0 as a new public
dependency of lithos-llm. No package version was added or removed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 22:07:00 -04:00

157 lines
6.7 KiB
Text

---
title: "OpenRouter"
description: "Route Fabro models through OpenRouter's multi-provider gateway"
---
[OpenRouter](https://openrouter.ai/) is an aggregator that fronts hundreds of models behind one OpenAI-compatible API. Fabro ships an enabled `openrouter` provider entry with a curated model catalog; it needs only an API key, and `settings.toml` can adjust it without changing Fabro code.
## Prerequisites
- An [OpenRouter account](https://openrouter.ai/) with credit for paid models
- An API key from [openrouter.ai/keys](https://openrouter.ai/keys)
## Enable the provider
Fabro runs execute through a Fabro server. Add the provider override to the settings file used by that server. For a local server, this is usually `~/.fabro/settings.toml`; for a remote deployment, update the server host's Fabro settings.
```toml title="settings.toml"
_version = 1
[llm.providers.openrouter]
enabled = true
```
## Configure credentials
Store the key in the target Fabro server vault:
```bash
fabro provider login --provider openrouter
# For a non-default remote server:
fabro provider login --server https://your-fabro.example --provider openrouter
# Or set the vault token directly:
fabro secret set OPENROUTER_API_KEY sk-or-v1-...
fabro secret --server https://your-fabro.example set OPENROUTER_API_KEY sk-or-v1-...
```
Direct SDK usage outside a Fabro server can use an env-backed credential source explicitly:
```bash
export OPENROUTER_API_KEY=sk-or-v1-...
```
## Included models
The built-in catalog gives OpenRouter offerings the same human-facing model slugs used by direct providers. Vendor-namespaced OpenRouter IDs remain opaque `api_model` values:
| Fabro model slug | OpenRouter API ID / notes |
| --- | --- |
| `claude-fable-5`, `claude-opus-5`, `claude-opus-4-8`, `claude-opus-4-7` | Matching `anthropic/...` API IDs; Anthropic-style cache billing |
| `claude-sonnet-4-6` | `anthropic/claude-sonnet-4.6`; provider default |
| `claude-haiku-4-5` | `anthropic/claude-haiku-4.5`; provider small default |
| `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.4`, `gpt-5.5` | Matching `openai/...` API IDs |
| `gemini-3.1-pro-preview`, `gemini-3.5-flash` | `google/...` API IDs |
| `deepseek-v4-pro`, `deepseek-v4-flash` (`deepseek`, `deepseek-v4`, `deepseek-flash`) | `deepseek/...` API IDs; Flash uses the `deepseek-v4-flash-0731` release |
| `kimi-k3`, `kimi-k2.6`, `qwen3-coder`, `qwen3.6-flash` | Vendor-prefixed API IDs |
| `laguna-s-2.1`, `laguna-xs-2.1` | `poolside/...`; native reasoning and tool use |
| `glm-5.2` (`glm`, `glm5`, `glm52`, `glm5.2`), `glm-4.6` | `z-ai/...` API IDs |
| `minimax-m2.7`, `mimo-v2.5-pro` | Vendor-prefixed API IDs |
| `nemotron-3-super-120b-a12b`, `devstral-2512` | Vendor-prefixed API IDs |
Any other OpenRouter model can be added under the provider. Choose a stable Fabro model slug as the table key and put OpenRouter's exact vendor/model string in `api_model`:
```toml title="settings.toml"
[llm.providers.openrouter.models."llama-4-maverick"]
display_name = "Llama 4 Maverick"
api_model = "meta-llama/llama-4-maverick"
limits = { context_tokens = 1000000, max_output_tokens = 16384 }
capabilities = { text = true, tools = true }
```
## Use OpenRouter models
```bash
fabro model list --provider openrouter
fabro model test --provider openrouter --model claude-sonnet-4-6
fabro run workflow.fabro --provider openrouter --model deepseek-v4-flash
```
When targeting a non-default remote server, pass the same `--server` value to verification commands:
```bash
fabro model list --server https://your-fabro.example --provider openrouter
fabro model test --server https://your-fabro.example --model anthropic/claude-sonnet-4-6
```
In workflow stylesheets:
```dot title="workflow.fabro"
digraph Example {
graph [
model_stylesheet="
* { model: anthropic/claude-sonnet-4-6; }
"
]
start [shape=Mdiamond, label="Start"]
work [label="Work", prompt="Use the configured OpenRouter model."]
exit [shape=Msquare, label="Exit"]
start -> work -> exit
}
```
## Cost telemetry
Every OpenRouter response includes an inline `usage.cost` with authoritative USD billing. Fabro surfaces it as the response `cost` with source `provider`. Other providers populate the same field from catalog price estimates with source `catalog`.
The catalog prices on OpenRouter model rows are best-effort estimates used only before the authoritative figure arrives (for example, mid-stream rollups).
## Provider routing
OpenRouter's [provider routing preferences](https://openrouter.ai/docs/guides/routing/provider-selection) pass through verbatim via `provider_options.openrouter` on API/SDK requests — the keys merge into the top level of the request body:
```json
{
"model": "anthropic/claude-sonnet-4-6",
"provider_options": {
"openrouter": {
"provider": { "sort": "throughput", "data_collection": "deny" },
"models": ["anthropic/claude-sonnet-4.6", "deepseek/deepseek-v4-pro"]
}
}
}
```
## Attribution headers
Fabro does not send OpenRouter's optional attribution headers (`HTTP-Referer`, `X-Title`) by default, so self-hosted installations stay anonymous on OpenRouter's public app leaderboard. Workflow runs do send `x-session-id: <run-id>` for request grouping; an explicit provider `default_headers` value for that header takes precedence. To opt in to attribution:
```toml title="settings.toml"
[llm.providers.openrouter.default_headers]
"HTTP-Referer" = "https://your-site.example"
"X-Title" = "Your App"
```
## Troubleshooting
**"No API key configured"** — Set the key on the target server with `fabro provider login --provider openrouter` or `fabro secret set OPENROUTER_API_KEY ...`. For direct SDK usage outside a Fabro server, export `OPENROUTER_API_KEY` in the invoking shell.
**"provider 'openrouter' is not configured in the server model catalog"** — Confirm the server host's `settings.toml` has `[llm.providers.openrouter]` with `enabled = true`. Fabro live-reloads `settings.toml` within a few seconds; after that, `fabro model list --provider openrouter` against the same server should show the enabled catalog.
**402 / insufficient credits** — Paid OpenRouter models require prepaid credit; check your balance at [openrouter.ai/credits](https://openrouter.ai/credits).
**Unknown model** — Confirm the model's `api_model` matches an OpenRouter slug exactly (including the vendor prefix), then run `fabro model test --model <fabro-model-id>`.
## Further reading
<Columns cols={2}>
<Card title="Models" icon="microchip" href="/core-concepts/models">
How Fabro routes model IDs, providers, and fallbacks.
</Card>
<Card title="Settings Configuration" icon="gear" href="/reference/user-configuration">
Full reference for provider settings and provider-scoped model offerings.
</Card>
</Columns>