Compare commits

...

3 Commits

Author SHA1 Message Date
Markus Hartung
bfeb4cfe15 docs(providers): regenerate PROVIDER_REFERENCE.md after porting #11538 2026-08-26 08:16:39 -03:00
Felix Wunderlich
afae88f577 feat(providers): opper logo, aggregator tag, regenerated reference and golden snapshot
(cherry picked from commit 9aacef7d6a)
2026-08-26 08:16:35 -03:00
Felix Wunderlich
f5f6158193 feat(providers): add Opper as an API-key gateway provider
Added Opper as an API-key gateway provider to OmniRoute. Five files changed:

1. `src/shared/constants/providers/apikey/gateways.ts` — new `opper` entry inserted immediately before `requesty` (same family: multi-model gateway, `passthroughModels: true`), matching the exact field shape of `requesty` and `openrouter`.
2. `open-sse/config/providers/registry/opper/index.ts` — new registry file using `buildOpenAiCompatibleRegistryEntry`, identical pattern to `requesty/index.ts`; base URL `https://api.opper.ai/v3/compat/chat/completions`, models URL `https://api.opper.ai/v3/compat/models`, empty static seed (live catalog via passthrough).
3. `open-sse/config/providers/index.ts` — import + REGISTRY key `opper` added adjacent to `requesty`.
4. `tests/unit/opper-provider.test.ts` — four unit tests mirroring `requesty-provider.test.ts`: catalog entry shape, registry entry shape, empty static seed, and passthrough model-id acceptance.
5. `changelog.d/features/opper-provider.md` — changelog fragment following the project's `changelog.d/` convention (never editing `CHANGELOG.md` directly).

(cherry picked from commit d976823672)
2026-08-26 08:16:31 -03:00
9 changed files with 103 additions and 5 deletions

View File

@@ -0,0 +1 @@
- **feat(providers):** Add **Opper** as an API-key gateway provider — EU-hosted AI gateway with 700+ models from 30+ providers behind one OpenAI-compatible API and one key (`OPPER_API_KEY`); model ids use `provider/model` format (e.g. `anthropic/claude-sonnet-4-6`, `openai/gpt-5`); live model catalog at `https://api.opper.ai/v3/compat/models`; entry mirrors `requesty` (same shape, `passthroughModels: true`, no static seed)

View File

@@ -1,16 +1,16 @@
---
title: "Provider Reference"
version: 3.8.51
lastUpdated: 2026-08-25
lastUpdated: 2026-08-26
---
# Provider Reference
> **Auto-generated** from `src/shared/constants/providers.ts` — do not edit by hand.
> Regenerate with: `npm run gen:provider-reference`
> **Last generated:** 2026-08-25
> **Last generated:** 2026-08-26
Total providers: **353**. See category breakdown below.
Total providers: **354**. See category breakdown below.
## Categories
@@ -98,7 +98,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
| `deepseek-web` | `ds-web` | DeepSeek Web | Web cookie | [link](https://chat.deepseek.com) | Paste your userToken from chat.deepseek.com — DevTools → Application → Local Storage → userToken | emulated |
| `doubao-web` | `db` | Dola Web (ByteDance) | Web cookie | [link](https://www.dola.com) | Paste the full Cookie header from www.dola.com. It should include sessionid, ttwid, and s_v_web_id. If s_v_web_id is unavailable, fp=verify_... from a chat/completion request URL can be used as a fallback. | — |
| `gemini-business` | `gembiz` | Gemini Business (Enterprise) | Web cookie | [link](https://business.gemini.google) | From your enterprise account: open business.gemini.google/home/cid/{your-cid}, then copy __Secure-1PSID and __Secure-1PSIDTS cookies from DevTools → Application → Cookies. Paste as a cookie header below. | — |
| `gemini-web` | `gweb` | Gemini Web (Free) | Web cookie | [link](https://gemini.google.com) | Paste your __Secure-1PSID cookie value from gemini.google.com. Optionally add __Secure-1PSIDTS separated by semicolon. | emulated |
| `gemini-web` | `gweb` | Gemini Web (Free) | Web cookie | [link](https://gemini.google.com) | Paste the full cookie header, the __Secure-1PSID value, or the JSON export containing cookies from gemini.google.com. Include __Secure-1PSIDTS and __Secure-1PSIDCC when available. | emulated |
| `grok-web` | `gw` | Grok Web (Subscription) | Web cookie | [link](https://grok.com) | Paste the full grok.com cookie line from DevTools → Application → Cookies. Include both `sso` and `sso-rw` (e.g. `sso=...; sso-rw=...`) — Grok's anti-bot rejects `sso` on its own. | — |
| `hailuo-web` | `hailuo-web` | Hailuo Web (MiniMax) | Web cookie | [link](https://chat.minimax.io) | Open hailuo.ai, log in, then open DevTools → Application → Local Storage → copy the "_token" value. device_id/uuid fingerprint fields are derived automatically; if requests fail, re-capture _token (sessions can expire). | — |
| `huggingchat` | `huggingchat` | HuggingChat (Free) | Web cookie | [link](https://huggingface.co/chat) | Paste the full Cookie header from huggingface.co/chat (DevTools → Network → /chat/conversation → Request Headers → Cookie). It should include hf-chat and may also include token / aws-waf-token. | — |
@@ -122,7 +122,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
| `zai-web` | `zw` | Z.ai Web | Web cookie | [link](https://chat.z.ai) | Copy the "token" value from chat.z.ai → DevTools → Application → Local Storage. Do not copy cookies; OmniRoute handles the per-request CAPTCHA through its browser transport. | — |
| `zenmux-free` | `zmf` | ZenMux Free (Web) | Web cookie | [link](https://zenmux.ai) | Login at zenmux.ai, then export all cookies using EditThisCookie or Cookie-Editor and paste the full Cookie header string here. Refresh every ~30 days. | — |
## API Key Providers (paid / paid-with-free-credits) (233)
## API Key Providers (paid / paid-with-free-credits) (234)
| ID | Alias | Name | Tags | Website | Notes |
|----|-------|------|------|---------|-------|
@@ -284,6 +284,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
| `openference-api` | `ofa` | Openference API | API key | [link](https://openference.com) | Free plan: 3-day trial with open-source models — no credit card required |
| `openrouter` | `openrouter` | OpenRouter | API key, aggregator | [link](https://openrouter.ai) | Free models at $0/token with :free suffix - 20 RPM / 200 RPD |
| `openvecta` | `openvecta` | OpenVecta | API key | [link](https://openvecta.com) | Free credits on signup for OpenAI-compatible inference across LLMs, embeddings, and reasoning models |
| `opper` | `opper` | Opper | API key, aggregator | [link](https://opper.ai) | — |
| `orcarouter` | `orcarouter` | OrcaRouter | API key | [link](https://www.orcarouter.ai) | — |
| `ovhcloud` | `ovh` | OVHcloud AI | API key | [link](https://www.ovhcloud.com) | — |
| `perplexity` | `pplx` | Perplexity | API key | [link](https://www.perplexity.ai) | — |

View File

@@ -229,6 +229,7 @@ import { x5labProvider } from "./registry/x5lab/index.ts";
import { kenariProvider } from "./registry/kenari/index.ts";
import { navyProvider } from "./registry/navy/index.ts";
import { naraProvider } from "./registry/nara/index.ts";
import { opperProvider } from "./registry/opper/index.ts";
import { requestyProvider } from "./registry/requesty/index.ts";
import { sealionProvider } from "./registry/sealion/index.ts";
import { routewayProvider } from "./registry/routeway/index.ts";
@@ -500,6 +501,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
kenari: kenariProvider,
navy: navyProvider,
nara: naraProvider,
opper: opperProvider,
requesty: requestyProvider,
sealion: sealionProvider,
routeway: routewayProvider,

View File

@@ -0,0 +1,11 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const opperProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "opper",
alias: "opper",
baseUrl: "https://api.opper.ai/v3/compat/chat/completions",
modelsUrl: "https://api.opper.ai/v3/compat/models",
models: [],
passthroughModels: true,
});

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 315 315"><title>Opper</title><circle cx="157.5" cy="157.5" r="157.5" fill="#1B2E40"/><g transform="translate(63 63) scale(0.6)" fill="#FFFFFF"><path fill-rule="evenodd" clip-rule="evenodd" d="M159.78 315C71.53 315 0 244.49 0 157.5C0 -18.9499 159.78 0.650075 159.78 0.650075C159.78 87.2201 88.36 157.4 0.2 157.5C149.8 157.64 159.78 315 159.78 315ZM160.52 217.98C160.52 217.98 156.94 161.65 105.04 157.52C120.6 157.34 160.52 151.54 160.52 96.5601C160.52 151.54 200.44 157.34 216 157.52C164.1 161.65 160.52 217.98 160.52 217.98Z"/></g></svg>

After

Width:  |  Height:  |  Size: 592 B

View File

@@ -97,6 +97,7 @@ export const AGGREGATOR_PROVIDER_IDS = new Set([
"kilo-gateway",
"aimlapi",
"novita",
"opper",
"piapi",
"getgoapi",
"laozhang",

View File

@@ -99,6 +99,20 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
freeNote: "Free models at $0/token with :free suffix - 20 RPM / 200 RPD",
serviceKinds: ["llm", "imageToText"],
},
opper: {
id: "opper",
alias: "opper",
name: "Opper",
icon: "router",
color: "#6366F1",
textIcon: "OP",
passthroughModels: true,
website: "https://opper.ai",
apiHint:
"Create an API key at https://platform.opper.ai, then paste it here as a Bearer token. " +
"OpenAI-compatible endpoint at https://api.opper.ai/v3/compat, with a live /v3/compat/models catalog. " +
"Model ids use provider/model format, e.g. anthropic/claude-sonnet-4-6 or openai/gpt-5.",
},
requesty: {
id: "requesty",
alias: "requesty",

View File

@@ -4609,6 +4609,29 @@
"stream": "https://api.openvecta.com/v1/chat/completions"
}
},
"opper": {
"format": "openai",
"headers": {
"apiKey": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"nonStream": {
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
},
"oauth": {
"Accept": "text/event-stream",
"Authorization": "Bearer <TOK>",
"Content-Type": "application/json"
}
},
"url": {
"nonStream": "https://api.opper.ai/v3/compat/chat/completions",
"stream": "https://api.opper.ai/v3/compat/chat/completions"
}
},
"orcarouter": {
"format": "openai",
"headers": {

View File

@@ -0,0 +1,44 @@
import test from "node:test";
import assert from "node:assert/strict";
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
const { REGISTRY: providerRegistry } = await import("../../open-sse/config/providerRegistry.ts");
const { isValidModel } = await import("../../src/shared/constants/models.ts");
const OPPER_CHAT_URL = "https://api.opper.ai/v3/compat/chat/completions";
const OPPER_MODELS_URL = "https://api.opper.ai/v3/compat/models";
test("opper is registered as an API-key gateway provider", () => {
const entry = APIKEY_PROVIDERS.opper;
assert.ok(entry, "APIKEY_PROVIDERS.opper must be defined");
assert.equal(entry.id, "opper");
assert.equal(entry.alias, "opper");
assert.equal(entry.name, "Opper");
assert.equal(entry.website, "https://opper.ai");
assert.equal(entry.passthroughModels, true);
});
test("opper registry entry uses OpenAI format with bearer API-key auth", () => {
const entry = providerRegistry.opper;
assert.ok(entry, "providerRegistry.opper must be defined");
assert.equal(entry.id, "opper");
assert.equal(entry.alias, "opper");
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.authType, "apikey");
assert.equal(entry.authHeader, "bearer");
assert.equal(entry.baseUrl, OPPER_CHAT_URL);
assert.equal(entry.modelsUrl, OPPER_MODELS_URL);
assert.equal(entry.passthroughModels, true);
});
test("opper ships no static model seed — relies fully on passthrough + live catalog", () => {
assert.deepEqual(providerRegistry.opper.models, []);
});
test("opper accepts provider/model ids via passthrough (OpenAI, Anthropic, DeepSeek, Mistral behind one key)", () => {
assert.equal(isValidModel("opper", "anthropic/claude-sonnet-4-6"), true);
assert.equal(isValidModel("opper", "openai/gpt-5"), true);
assert.equal(isValidModel("opper", "deepseek/deepseek-v4-pro"), true);
assert.equal(isValidModel("opper", "mistral/mistral-large-latest"), true);
});