From f076a3646ed0dcf12982df38c2481f6b782bc1fa Mon Sep 17 00:00:00 2001 From: Scott Werner Date: Wed, 27 May 2026 13:11:12 -0400 Subject: [PATCH] docs: document OpenRouter integration Add a dedicated integration page covering enable, credentials, the 17 included models, and pass-through of OpenRouter-specific request fields via provider_options.openrouter. Add a brief mention to core-concepts/models.mdx pointing to the integration page, and a dated changelog entry. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/public/changelog/2026-05-28.mdx | 52 +++++++++ docs/public/core-concepts/models.mdx | 7 ++ docs/public/docs.json | 3 + docs/public/integrations/openrouter.mdx | 134 ++++++++++++++++++++++++ 4 files changed, 196 insertions(+) create mode 100644 docs/public/changelog/2026-05-28.mdx create mode 100644 docs/public/integrations/openrouter.mdx diff --git a/docs/public/changelog/2026-05-28.mdx b/docs/public/changelog/2026-05-28.mdx new file mode 100644 index 000000000..edd4921dd --- /dev/null +++ b/docs/public/changelog/2026-05-28.mdx @@ -0,0 +1,52 @@ +--- +title: "OpenRouter as an opt-in provider" +date: "2026-05-28" +--- + +## OpenRouter ships as a built-in opt-in provider + +Fabro now includes [OpenRouter](https://openrouter.ai) as a built-in catalog provider. OpenRouter is an OpenAI-compatible gateway that proxies many model providers behind a single API and one billing account. The catalog ships disabled — flip a single toggle in `~/.fabro/settings.toml` to opt in: + +```toml +[llm.providers.openrouter] +enabled = true +``` + +Then run `fabro provider login openrouter` (or set `OPENROUTER_API_KEY`) and the 17 curated models become available with no further configuration. + +## Curated model catalog + +Unlike LiteLLM or Ollama — where you declare the models your proxy serves — Fabro ships the OpenRouter catalog for you. The starter set covers the three majors plus the most popular open-weights models on OpenRouter: + +- Anthropic: Claude Opus 4.7, Sonnet 4.6, Haiku 4.5 +- OpenAI: GPT-5.4, GPT-5.5 +- Google: Gemini 3.1 Pro Preview, Gemini 3.5 Flash +- Open-weights: Xiaomi MiMo v2.5 Pro, MiniMax M2.7, DeepSeek V4 Pro/Flash, Kimi K2.6, Qwen3 Coder, Qwen3.6 Flash, GLM 4.6, Nemotron 3 Super 120B, Devstral 2512 + +Model IDs use OpenRouter's vendor-namespaced slug convention so they don't collide with direct-provider entries: + +```bash +fabro model list --provider openrouter +fabro run workflow.fabro --model deepseek/deepseek-v4-flash +fabro run workflow.fabro --model anthropic/claude-sonnet-4-6 +``` + +## Typed workflow attrs for OpenRouter routing + +Five `openrouter_*` stage attrs let you steer OpenRouter's provider routing from `workflow.fabro` stylesheets without dropping to the API: `openrouter_provider_sort`, `openrouter_fallback_models`, `openrouter_transforms`, `openrouter_allow_fallbacks`, `openrouter_data_collection`. Power users calling `POST /api/v1/completions` directly can continue to set `provider_options.openrouter` for the full set of OpenRouter request fields. + +## Authoritative cost telemetry + +Every OpenRouter response includes an inline `usage.cost` field with authoritative USD billing. Fabro surfaces this as `Response.cost_usd` with `cost_source = "authoritative"`. Direct providers populate the same field from catalog prices with `cost_source = "estimated"`. + +## More + + +- New `cost_usd` and `cost_source` fields on `CompletionResponse` (also surfaced in the generated TypeScript client) +- New `OPENROUTER_API_KEY` recognized as an optional vault secret across CLI and server code paths + + + +- The OpenAI-compatible adapter now parses `prompt_tokens_details.cached_tokens` and `cache_write_tokens` from provider responses, which keeps cached-token cost math accurate for any OpenAI-compatible provider that emits them +- Refactored the OpenAI-Chat-Completions wire layer into a shared `openai_chat` module so OpenRouter and OpenAI-compatible providers reuse one HTTP pipeline + diff --git a/docs/public/core-concepts/models.mdx b/docs/public/core-concepts/models.mdx index e07e37339..e780026c3 100644 --- a/docs/public/core-concepts/models.mdx +++ b/docs/public/core-concepts/models.mdx @@ -114,6 +114,13 @@ vision = false reasoning = false ``` +For [OpenRouter](/integrations/openrouter), Fabro ships a disabled provider entry with 17 curated models. Enable it with a single section in settings — no model declarations needed: + +```toml title="settings.toml" +[llm.providers.openrouter] +enabled = true +``` + `api_id` is the model name sent to the provider API. Omit it when the Fabro model ID and provider model ID are the same. Model roles are separate: `default = true` controls normal model selection for workflow execution, while `small_default = true` marks the provider's small/cheap utility model for metadata tasks such as generated run titles. If a provider has no small default, Fabro falls back to that provider's normal default. diff --git a/docs/public/docs.json b/docs/public/docs.json index c60ddb57b..2a3052682 100644 --- a/docs/public/docs.json +++ b/docs/public/docs.json @@ -94,6 +94,7 @@ "integrations/github", "integrations/daytona", "integrations/litellm", + "integrations/openrouter", "integrations/slack", "integrations/brave-search" ] @@ -255,6 +256,8 @@ "group": "May 2026", "icon": "clock-rotate-left", "pages": [ + "changelog/2026-05-28", + "changelog/2026-05-27", "changelog/2026-05-26", "changelog/2026-05-25", "changelog/2026-05-24", diff --git a/docs/public/integrations/openrouter.mdx b/docs/public/integrations/openrouter.mdx new file mode 100644 index 000000000..a4a5564a9 --- /dev/null +++ b/docs/public/integrations/openrouter.mdx @@ -0,0 +1,134 @@ +--- +title: "OpenRouter" +description: "Route Fabro models through OpenRouter to access many models with a single API key" +--- + +[OpenRouter](https://openrouter.ai) is an OpenAI-compatible gateway that proxies many model providers behind one API and one billing account. Fabro includes a disabled `openrouter` provider entry with a curated catalog of 17 models so you can opt in from `settings.toml` without changing Fabro code. + +## Prerequisites + +- An OpenRouter account +- An OpenRouter API key from [openrouter.ai/keys](https://openrouter.ai/keys) + +## Enable the provider + +Add the provider override to `~/.fabro/settings.toml`: + +```toml title="settings.toml" +_version = 1 + +[llm.providers.openrouter] +enabled = true +``` + +That's the entire configuration — Fabro ships the model catalog, base URL, and attribution headers for you. + +## Configure credentials + +For server-backed runs, store `OPENROUTER_API_KEY` in the Fabro server vault: + +```bash +fabro provider login openrouter +``` + +Or via the generic secret command: + +```bash +fabro secret set OPENROUTER_API_KEY sk-or-v1-... +``` + +Standalone local SDK/CLI runs can use an env-backed credential source: + +```bash +export OPENROUTER_API_KEY=sk-or-v1-... +``` + +## Included models + +The 17 models below ship with the provider. Use the Fabro model ID (left column) in workflows or on the CLI; Fabro sends OpenRouter's slug (right column) over the wire. + +| Fabro model ID | OpenRouter slug | +| --- | --- | +| `anthropic/claude-opus-4-7` | `anthropic/claude-opus-4.7` | +| `anthropic/claude-sonnet-4-6` | `anthropic/claude-sonnet-4.6` | +| `anthropic/claude-haiku-4-5` | `anthropic/claude-haiku-4.5` | +| `openai/gpt-5.4` | `openai/gpt-5.4` | +| `openai/gpt-5.5` | `openai/gpt-5.5` | +| `google/gemini-3.1-pro-preview` | `google/gemini-3.1-pro-preview` | +| `google/gemini-3.5-flash` | `google/gemini-3.5-flash` | +| `xiaomi/mimo-v2.5-pro` | `xiaomi/mimo-v2.5-pro` | +| `minimax/minimax-m2.7` | `minimax/minimax-m2.7` | +| `deepseek/deepseek-v4-pro` | `deepseek/deepseek-v4-pro` | +| `deepseek/deepseek-v4-flash` | `deepseek/deepseek-v4-flash` | +| `moonshotai/kimi-k2.6` | `moonshotai/kimi-k2.6` | +| `qwen/qwen3-coder` | `qwen/qwen3-coder` | +| `qwen/qwen3.6-flash` | `qwen/qwen3.6-flash` | +| `z-ai/glm-4.6` | `z-ai/glm-4.6` | +| `nvidia/nemotron-3-super-120b-a12b` | `nvidia/nemotron-3-super-120b-a12b` | +| `mistralai/devstral-2512` | `mistralai/devstral-2512` | + +The default model is `anthropic/claude-sonnet-4-6`. The small default (used for utility tasks like generated run titles) is `anthropic/claude-haiku-4-5`. + +## Use OpenRouter models + +```bash +fabro model list --provider openrouter +fabro model test --model anthropic/claude-sonnet-4-6 +fabro run workflow.fabro --model deepseek/deepseek-v4-flash +``` + +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 +} +``` + +## Provider routing (advanced) + +OpenRouter accepts top-level request fields that aren't part of the OpenAI Chat Completions schema, such as `provider` (routing preferences), `models` (fallback list), `transforms`, and `plugins`. Fabro forwards these through the existing `provider_options.openrouter` request field when calling the API directly: + +```json +{ + "model": "anthropic/claude-sonnet-4-6", + "messages": [...], + "provider_options": { + "openrouter": { + "provider": { "sort": "throughput" }, + "models": ["openai/gpt-5.5", "google/gemini-3.1-pro-preview"] + } + } +} +``` + +See [OpenRouter's provider routing documentation](https://openrouter.ai/docs/features/provider-routing) for the full set of supported fields. + +## Troubleshooting + +**"No API key configured"** — For server-backed runs, set `vault:OPENROUTER_API_KEY` with `fabro provider login openrouter`. For standalone local usage, export `OPENROUTER_API_KEY` in the invoking shell. + +**"Provider not enabled"** — Confirm `[llm.providers.openrouter]` has `enabled = true` in your `settings.toml`. + +**Model not found** — Check that the OpenRouter slug for the model is still current at [openrouter.ai/models](https://openrouter.ai/models). Vendors occasionally rename or deprecate slugs. + +## Further reading + + + + How Fabro routes model IDs, providers, and fallbacks. + + + Full reference for `[llm.providers.]` and `[llm.models.]`. + +