mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-10-19 13:30:37 +00:00
fix(auto): honor provider ToS for uncataloged models (#15979)
Batch-merged with the owner's 2026-10-09 PR wave (/merge-batch). Validated in one combined tree of 57 boarded PRs on top of release/v3.8.52 (35ef635c): typecheck:core, check:open-sse-typecheck, check-deps, changelog-integrity, complexity + cognitive ratchets, check:docs-all, i18n UI coverage, ESLint on all 247 changed source files — all green for this wave; 89 focused unit test files (739/744 pass under node:test, the 4 UI .tsx files re-run under vitest 13/13, check-deps fixed in #15912). Remaining reds in that tree belong only to held/draft PRs outside this wave (#15790 file-size, #15780 open-sse types).
This commit is contained in:
parent
4e26348956
commit
f1f866d7c6
9 changed files with 173 additions and 45 deletions
21
README.md
21
README.md
|
|
@ -13,10 +13,12 @@
|
|||
|
||||
<div align="center">
|
||||
|
||||
## 💰 ~1.62B Free Tokens / Month
|
||||
## 💰 ~1.62B Tokens / Month Across Third-Party Free Tiers
|
||||
|
||||
</div>
|
||||
|
||||
> **Bring your own provider accounts.** This is an estimated aggregate across separately eligible third-party free tiers, not a token grant from OmniRoute. Sign up, obtain credentials where required, and connect the providers you can use; each provider controls its limits, availability, and terms.
|
||||
>
|
||||
> Stacking free tiers by hand is painful — dozens of SDKs, dozens of rate limits, and no idea how much you actually have. OmniRoute catalogs **489 free-tier entries across 35 recurring pool keys** and computes the token headline from the **17 pools with a published positive monthly budget plus five per-model Groq caps**, deduplicated by shared pool. Quotas that only open after a regional identity check (today: ModelScope) are shown apart, +~6M behind regional identity verification, and never summed into the headline. The result stays visible on the dashboard (`/dashboard/free-tiers`).
|
||||
|
||||
<img src="./docs/diagrams/free-tier-budget.svg" width="100%" alt="OmniRoute free-tier budget card: ~1.62B free tokens per month steady, up to ~2.22B in the first month with signup credits, from 35 documented recurring pool keys covering 489 cataloged free-tier entries behind one endpoint. Honest pool-deduped math — each shared pool counted once, including 17 recurring pools with a published positive monthly token budget plus five per-model Groq caps; 13 providers are marked avoid in the terms-risk catalog so you decide. Budget bar includes Mistral 1B, Nara 210M, LLM7 150M, xKiro 150M, Groq 30M (five per-model caps) and smaller pools, plus first-month signup credits and permanently-free no-token-cap providers surfaced separately so they never inflate the headline. Live used/remaining on /dashboard/free-tiers."/>
|
||||
|
|
@ -209,20 +211,21 @@
|
|||
|
||||
<div align="center">
|
||||
|
||||
## 🆓 Works the second you install it — no keys, no config
|
||||
## 🆓 Install, connect a provider, then route through one endpoint
|
||||
|
||||
</div>
|
||||
|
||||
<img src="./docs/diagrams/works-zero-config.svg" width="100%" alt="Works the second you install it — zero config. Three steps: 1. Install — npm i -g omniroute, server boots on localhost:20128. 2. Point your tool at http://localhost:20128/v1 — any OpenAI-compatible tool (Claude Code, Cursor, Cline). 3. It answers — call model auto for an instant reply, with no API key, no signup, no configuration. Keyless provider OpenCode Free is pre-wired into the auto combo, so a fresh install responds out of the box."/>
|
||||
<img src="./docs/diagrams/works-zero-config.svg" width="100%" alt="Three steps: install and start OmniRoute, connect an eligible provider with your own account or API key, then point your tool at localhost:20128/v1 using an OmniRoute API key and model auto. Routing depends on available eligible connections and provider limits."/>
|
||||
|
||||
```bash
|
||||
# Fresh install, zero credentials — `auto` already works:
|
||||
# After connecting a provider, copy your OmniRoute key from Dashboard → Endpoints:
|
||||
curl http://localhost:20128/v1/chat/completions \
|
||||
-H "Authorization: Bearer YOUR_OMNIROUTE_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"model":"auto","messages":[{"role":"user","content":"Hello!"}]}'
|
||||
```
|
||||
|
||||
<sub>Prefer a specific free backend? Call `oc/…` (OpenCode Free) directly. Then graduate to `auto` and let OmniRoute pick.</sub>
|
||||
<sub>`auto` needs an eligible route. A fresh installation can have no eligible keyless targets, and a keyless provider may reject third-party clients. Providers marked `tos: avoid`, including OpenCode Free and Kiro, are excluded from automatic routing by default; connecting an account does not override that setting. See the [Free Tiers Guide](docs/getting-started/FREE-TIERS-GUIDE.md) before choosing a provider.</sub>
|
||||
|
||||
<sub>📦 Copy-paste quickstart scripts for **Python, Node.js, PHP, and cURL** → [`examples/quickstart/`](examples/quickstart/)</sub>
|
||||
|
||||
|
|
@ -728,7 +731,7 @@ of your shell history. → [CLI Integrations](docs/guides/CLI-INTEGRATIONS.md)
|
|||
<td align="center" width="150"><img src="./public/providers/pollinations.svg" width="42" alt="Pollinations"/><br/><b>Pollinations</b><br/><sub>GPT, Llama, Claude<br/>No key needed</sub></td>
|
||||
<td align="center" width="150"><img src="./public/providers/cloudflare.svg" width="42" alt="Cloudflare AI"/><br/><b>Cloudflare AI</b><br/><sub>50+ models<br/>10K neurons/day</sub></td>
|
||||
<td align="center" width="150"><img src="./public/providers/nvidia.svg" width="42" alt="NVIDIA NIM"/><br/><b>NVIDIA NIM</b><br/><sub>GLM, MiniMax<br/>~40 RPM free</sub></td>
|
||||
<td align="center" width="150"><img src="./public/providers/cerebras.svg" width="42" alt="Cerebras"/><br/><b>Cerebras</b><br/><sub>GLM 4.7, GPT-OSS<br/>1M tokens/day</sub></td>
|
||||
<td align="center" width="150"><img src="./public/providers/cerebras.svg" width="42" alt="Cerebras"/><br/><b>Cerebras</b><br/><sub>GLM 4.7, GPT-OSS<br/>One-time $5 credit; card required</sub></td>
|
||||
<td align="center" width="150"><img src="./public/providers/openrouter.svg" width="42" alt="OpenRouter"/><br/><b>OpenRouter</b><br/><sub>:free models<br/>+$10 → higher RPM</sub></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
@ -1030,16 +1033,16 @@ omniroute
|
|||
|
||||
Dashboard at `http://localhost:20128` · API at `http://localhost:20128/v1`.
|
||||
|
||||
**2) Connect a FREE provider (no signup)**
|
||||
**2) Connect an eligible provider using your own account**
|
||||
|
||||
Dashboard → **Providers** → connect **Kiro AI** (free Claude, ~50 credits/month per account) or **OpenCode Free** (no auth) → done.
|
||||
Dashboard → **Providers** → choose a provider whose current terms and quota fit your use case → add its API key or complete its account flow. Free tiers may require signup, approval, or a payment method. Review the [Free Tiers Guide](docs/getting-started/FREE-TIERS-GUIDE.md); keyless availability is not guaranteed, and providers marked `tos: avoid` are excluded from `auto` by default.
|
||||
|
||||
**3) Point your coding tool**
|
||||
|
||||
```txt
|
||||
Base URL: http://localhost:20128/v1
|
||||
API Key: [copy from Dashboard → Endpoints]
|
||||
Model: auto (zero-config smart routing — or any provider/model)
|
||||
Model: auto (routes among eligible connections — or choose provider/model)
|
||||
```
|
||||
|
||||
**4) Verify it's working**
|
||||
|
|
|
|||
1
changelog.d/fixes/15059-first-run-expectations.md
Normal file
1
changelog.d/fixes/15059-first-run-expectations.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
- Apply the provider's ToS verdict to auto-routing candidates missing from the per-model budget catalog, and clarify first-run setup, account requirements, promotional credits, and aggregate free-tier estimates (#15059).
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<svg viewBox="0 0 1200 430" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Works the second you install it — zero config. Three steps: 1. Install — npm install -g omniroute, one command, server on localhost port 20128. 2. Point your tool at http://localhost:20128/v1 — any OpenAI-compatible tool. 3. It answers — call model auto and get an instant reply with no API key, no signup, no configuration. Keyless provider OpenCode Free is pre-wired into the auto combo, so a fresh install responds out of the box.">
|
||||
<desc>Animated flow card: three step tiles (Install, Point your tool, It answers) fade in left to right, a dot travels along the connectors between them in a loop, and the final check pulses.</desc>
|
||||
<svg viewBox="0 0 1200 430" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Install and start OmniRoute, connect an eligible provider with your own account, then configure your tool. Auto routing depends on eligible connections and provider limits.">
|
||||
<desc>Animated flow card: three step tiles (Install and start, Connect provider, Use your tool) fade in left to right, a dot travels along the connectors between them in a loop, and the final check pulses.</desc>
|
||||
<defs>
|
||||
<pattern id="gridW" width="32" height="32" patternUnits="userSpaceOnUse">
|
||||
<path d="M 32 0 L 0 0 0 32" fill="none" stroke="#ffffff" stroke-opacity="0.06" stroke-width="1"/>
|
||||
|
|
@ -16,9 +16,9 @@
|
|||
<rect width="1200" height="430" fill="url(#bgGlowW)"/>
|
||||
|
||||
<!-- header -->
|
||||
<text x="40" y="56" font-family="Consolas, 'Courier New', monospace" font-size="13" letter-spacing="2.5" fill="#7ee787">WORKS THE SECOND YOU INSTALL IT</text>
|
||||
<text x="40" y="56" font-family="Consolas, 'Courier New', monospace" font-size="13" letter-spacing="2.5" fill="#7ee787">CONNECT, THEN ROUTE</text>
|
||||
<line x1="392" y1="51" x2="1160" y2="51" stroke="#232b38" stroke-width="1.5"/>
|
||||
<text x="40" y="98" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="23" font-weight="600" fill="#c9d1d9">Fresh install → it already answers. <tspan fill="#7ee787" font-weight="800">Zero config.</tspan></text>
|
||||
<text x="40" y="98" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="23" font-weight="600" fill="#c9d1d9">Install → connect a provider → <tspan fill="#7ee787" font-weight="800">route.</tspan></text>
|
||||
|
||||
<!-- connectors (drawn under the tiles) -->
|
||||
<g stroke="#2b3543" stroke-width="2" stroke-dasharray="5 5" fill="none">
|
||||
|
|
@ -52,9 +52,9 @@
|
|||
<path d="M 11 2 L 11 15 M 6 10 L 11 15 L 16 10"/>
|
||||
<path d="M 3 19 L 19 19"/>
|
||||
</g>
|
||||
<text x="140" y="179" font-size="18" font-weight="800" fill="#74b9ff">Install</text>
|
||||
<text x="140" y="179" font-size="18" font-weight="800" fill="#74b9ff">Install and start</text>
|
||||
<text x="66" y="222" font-family="Consolas, 'Courier New', monospace" font-size="14" fill="#e6edf3">$ npm i -g omniroute</text>
|
||||
<text x="66" y="258" font-size="13.5" fill="#a1a1aa">One command. Server boots on</text>
|
||||
<text x="66" y="258" font-size="13.5" fill="#a1a1aa">Then run omniroute; open</text>
|
||||
<text x="66" y="279" font-family="Consolas, 'Courier New', monospace" font-size="13" fill="#8b949e">localhost:20128</text>
|
||||
</g>
|
||||
|
||||
|
|
@ -68,10 +68,10 @@
|
|||
<g transform="translate(503,161)" stroke="#a78bfa" stroke-width="2.2" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M 8 6 L 5 9 A 4 4 0 0 0 5 15 L 8 18 M 14 6 L 17 9 A 4 4 0 0 1 17 15 L 14 18 M 8.5 12 L 13.5 12"/>
|
||||
</g>
|
||||
<text x="535" y="179" font-size="18" font-weight="800" fill="#a78bfa">Point your tool</text>
|
||||
<text x="461" y="222" font-family="Consolas, 'Courier New', monospace" font-size="13" fill="#e6edf3">http://localhost:20128/v1</text>
|
||||
<text x="461" y="258" font-size="13.5" fill="#a1a1aa">Any OpenAI-compatible tool —</text>
|
||||
<text x="461" y="279" font-size="13.5" fill="#a1a1aa">Claude Code, Cursor, Cline…</text>
|
||||
<text x="535" y="179" font-size="18" font-weight="800" fill="#a78bfa">Connect provider</text>
|
||||
<text x="461" y="222" font-family="Consolas, 'Courier New', monospace" font-size="13" fill="#e6edf3">Dashboard → Providers</text>
|
||||
<text x="461" y="258" font-size="13.5" fill="#a1a1aa">Use your own account or API key.</text>
|
||||
<text x="461" y="279" font-size="13.5" fill="#a1a1aa">Review provider terms and limits.</text>
|
||||
</g>
|
||||
|
||||
<!-- step 3: it answers (green) -->
|
||||
|
|
@ -87,10 +87,10 @@
|
|||
<g transform="translate(898,161)" stroke="#7ee787" stroke-width="2.4" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M 3 11 L 9 17 L 19 5"/>
|
||||
</g>
|
||||
<text x="930" y="179" font-size="18" font-weight="800" fill="#7ee787">It answers</text>
|
||||
<text x="856" y="222" font-family="Consolas, 'Courier New', monospace" font-size="14" fill="#e6edf3">model: <tspan fill="#7ee787" font-weight="700">"auto"</tspan> → reply</text>
|
||||
<text x="856" y="258" font-size="13.5" fill="#a1a1aa">Instant. OmniRoute builds a virtual</text>
|
||||
<text x="856" y="279" font-size="13.5" fill="#a1a1aa">combo from keyless free providers.</text>
|
||||
<text x="930" y="179" font-size="18" font-weight="800" fill="#7ee787">Use your tool</text>
|
||||
<text x="856" y="222" font-family="Consolas, 'Courier New', monospace" font-size="14" fill="#e6edf3">localhost:20128/v1</text>
|
||||
<text x="856" y="258" font-size="13.5" fill="#a1a1aa">Set model to "auto"</text>
|
||||
<text x="856" y="279" font-size="13.5" fill="#a1a1aa">Eligible connections + fallback.</text>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
|
|
@ -99,19 +99,19 @@
|
|||
<animate attributeName="opacity" values="0;1" dur="0.5s" begin="1.3s" fill="freeze"/>
|
||||
<g transform="translate(40,332)">
|
||||
<rect x="0" y="0" width="168" height="34" rx="17" fill="#161b22" stroke="#7ee787" stroke-opacity="0.35" stroke-width="1"/>
|
||||
<text x="24" y="22" fill="#c9d1d9">✕ no API key</text>
|
||||
<text x="24" y="22" fill="#c9d1d9">Your accounts</text>
|
||||
</g>
|
||||
<g transform="translate(224,332)">
|
||||
<rect x="0" y="0" width="168" height="34" rx="17" fill="#161b22" stroke="#7ee787" stroke-opacity="0.35" stroke-width="1"/>
|
||||
<text x="24" y="22" fill="#c9d1d9">✕ no signup</text>
|
||||
<text x="24" y="22" fill="#c9d1d9">Provider limits</text>
|
||||
</g>
|
||||
<g transform="translate(408,332)">
|
||||
<rect x="0" y="0" width="188" height="34" rx="17" fill="#161b22" stroke="#7ee787" stroke-opacity="0.35" stroke-width="1"/>
|
||||
<text x="24" y="22" fill="#c9d1d9">✕ no configuration</text>
|
||||
<text x="24" y="22" fill="#c9d1d9">Local routing</text>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- footer -->
|
||||
<text x="40" y="406" font-family="Consolas, 'Courier New', monospace" font-size="12" fill="#71717a">OpenCode Free is pre-wired into <tspan fill="#7ee787">auto</tspan> — a fresh install responds out of the box.</text>
|
||||
<text x="40" y="406" font-family="Consolas, 'Courier New', monospace" font-size="12" fill="#71717a"><tspan fill="#7ee787">auto</tspan> uses eligible connections; availability and provider limits still apply.</text>
|
||||
<text x="1160" y="406" text-anchor="end" font-family="Consolas, 'Courier New', monospace" font-size="12" letter-spacing="1.5" fill="#71717a">$0 · MIT</text>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 7.9 KiB |
|
|
@ -1,6 +1,6 @@
|
|||
# Free Tiers Guide: Understand and Combine Free AI Access
|
||||
|
||||
> **TL;DR**: OmniRoute registers 357 provider IDs, with **152 provider-catalog entries marked `hasFree`**. The stricter audited free-model catalog covers **35 recurring pool keys / 482 entries** (475 active + 7 discontinued). Connect several suitable providers for broader fallback capacity; every quota, approval rule, privacy policy, and paid-overage condition still applies.
|
||||
> **TL;DR**: Bring your own eligible provider accounts. OmniRoute combines the connections you configure; it does not issue the advertised aggregate token budget. Free access can require signup, an API key, approval, or a payment method. Provider limits, privacy policies, and terms still apply.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ mean a no-auth endpoint, recurring quota, rate-limited uncapped access, a signup
|
|||
manual approval, or a temporary promotion. Some options require an account, API key,
|
||||
credit card, KYC, or acceptance of provider-specific terms.
|
||||
|
||||
OmniRoute **aggregates** these free tiers into one endpoint. Instead of signing up for 10 different services, you connect them all to OmniRoute and use `model: "auto"` to automatically pick the best free option for each request.
|
||||
OmniRoute **aggregates** configured connections into one endpoint. You still sign up separately for each provider that requires an account. Connect those accounts and use `model: "auto"` to route among eligible targets. A fresh installation can have no eligible keyless target; installing OmniRoute alone does not guarantee a successful chat response.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -28,16 +28,16 @@ These providers have a recurring, keyless, or uncapped free-access path in the a
|
|||
| **Pollinations** | Current keyless model set; some former models are discontinued or key-required | Keyless; no published token cap | No provider credential for the keyless models |
|
||||
| **Logfare** | kimi-k3, deepseek-v4-pro, glm-5.2, gpt-5.6-luna, minimax-m3, and more | Free API key (no rate limits, no card); **every request is logged** for research (opt out at logfare.ai/consent) | Instant key at logfare.ai/register; ToS/privacy at logfare.ai/tos and logfare.ai/privacy |
|
||||
| **Cloudflare AI** | Workers AI catalog | Audited pool estimates ~30M tokens/month from published usage units | Cloudflare account and API credentials |
|
||||
| **Gemini** | Gemini Flash family | Audited pool estimates ~60M tokens/month | Google AI Studio API key; rate limits apply |
|
||||
| **Gemini** | Gemini Flash family | Variable project/model rate limits; no fixed monthly token grant is included in the headline | Google AI Studio API key; check the project’s active limits |
|
||||
| **Groq** | Llama, GPT-OSS, and Qwen models | Audited pool estimates ~15M tokens/month | Groq API key; rate limits apply |
|
||||
| **Cerebras** | GLM 4.7 and GPT-OSS 120B | Audited pool estimates ~30M tokens/month | Cerebras API key; rate limits apply |
|
||||
|
||||
### Signup Grants and Provider-Specific Credits
|
||||
|
||||
These providers give you **free credits** when you sign up:
|
||||
These providers offer signup grants or promotional credits, subject to their eligibility rules. As verified on 2026-10-08, [Cerebras pricing](https://www.cerebras.ai/pricing) requires a payment method for a one-time $5 credit that expires after 30 days; it is not a recurring token quota. [Gemini rate limits](https://ai.google.dev/gemini-api/docs/rate-limits) vary by project, model, and tier, so they are not converted into a guaranteed monthly token grant.
|
||||
|
||||
| Provider | Free Credits | Models | How to Get |
|
||||
| ------------- | ------------------------------------------------------------------ | ------------------------- | --------------------------------------------------------- |
|
||||
| **Cerebras** | One-time $5 promotional credit; expires after 30 days | Current inference catalog | Account and valid payment method |
|
||||
| **DeepSeek** | 5M free tokens | DeepSeek V4 | Sign up at platform.deepseek.com |
|
||||
| **LongCat** | 10M-token one-time grant | LongCat 2.0 | API key + KYC; pay-as-you-go after the grant |
|
||||
| **Vertex AI** | $300 signup credit represented as ~300M tokens in the budget model | Gemini and partner models | Google Cloud account; billing and eligibility rules apply |
|
||||
|
|
@ -73,7 +73,7 @@ Then use `model: "auto"` and OmniRoute will:
|
|||
- Try the highest-ranked eligible connection first
|
||||
- If its quota or health check fails → try the next configured provider
|
||||
- If the keyless provider is unavailable → continue through the remaining targets
|
||||
- If all fail → use LongCat as backup
|
||||
- If no eligible connection succeeds → return an error; signup credits are only usable while valid and available
|
||||
|
||||
**Result**: broader free-tier coverage with automatic fallback — not a guarantee of unlimited capacity.
|
||||
|
||||
|
|
@ -102,8 +102,7 @@ uncapped/keyless access, signup credits, discontinued entries, and higher-risk s
|
|||
|
||||
### Step 5: Click Connect
|
||||
|
||||
For a `NOAUTH` provider, no credential is required. OAuth and API-key providers must be
|
||||
connected through their documented account flow.
|
||||
For a `NOAUTH` provider, OmniRoute does not request an upstream credential. This does not guarantee that the upstream accepts third-party clients or has available capacity. OAuth and API-key providers must be connected through their documented account flow. Your client still uses the OmniRoute API key shown in **Dashboard → Endpoints** when router authentication is enabled.
|
||||
|
||||
### Step 6: Repeat
|
||||
|
||||
|
|
@ -120,7 +119,7 @@ Connect several providers whose terms and privacy model fit your use case.
|
|||
- `recurring-uncapped` means no published token ceiling was available; rate and
|
||||
concurrency limits still apply.
|
||||
- `one-time-initial` does not recur after the signup grant is consumed.
|
||||
- `tos: avoid` is a warning to review provider terms and account risk before use.
|
||||
- `tos: avoid` providers are excluded from automatic routing by default (`excludeTosAvoid`). Connecting an account does not bypass this filter. Any operator override should follow a review of provider terms and account risk.
|
||||
- Entries marked `discontinued` remain historical evidence and must not be presented as
|
||||
currently free.
|
||||
|
||||
|
|
@ -158,15 +157,12 @@ provider's quota or access policy.
|
|||
|
||||
The live, pool-deduplicated catalog currently reports:
|
||||
|
||||
| Metric | Current audited value | Interpretation |
|
||||
| ---------------------------------------------------- | -----------------------------------------------: | -------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Recurring quantified grant | **~1.62B tokens/month** | Shared pools counted once; excludes uncapped providers from the sum |
|
||||
| First month with signup grants | **~2.22B tokens** | Recurring total plus one-time and recurring credits |
|
||||
| Audited free-model inventory | **35 recurring pool keys / 482 catalog entries** | 475 active + 7 discontinued; distinct from the 357-provider catalog |
|
||||
| Recurring/keyless free-forever providers represented | **53** | Unique providers across recurring daily/monthly/credit/uncapped and keyless catalog types, eligibility-gated rows excluded |
|
||||
| Provider catalog entries marked `hasFree` | **152 / 357** | Broader provider metadata; not all have a quantifiable recurring quota |
|
||||
| Metric | Current audited value | Interpretation |
|
||||
| ------------------------------ | ----------------------: | ------------------------------------------------------------------- |
|
||||
| Recurring quantified grant | **~1.62B tokens/month** | Shared pools counted once; excludes uncapped providers from the sum |
|
||||
| First month with signup grants | **~2.22B tokens** | Recurring total plus one-time and recurring credits |
|
||||
|
||||
These values are computed from `open-sse/config/freeModelCatalog.ts`; see the
|
||||
These are catalog-wide estimates across separate eligible accounts, not an allowance supplied by OmniRoute or a prediction for a fresh installation. Your usable capacity depends on the providers you connect and their current conditions. The values are computed from `open-sse/config/freeModelCatalog.ts`; see the
|
||||
[Free Tiers Reference](../reference/FREE_TIERS.md) for pool deduplication, ToS flags,
|
||||
discontinued entries, and signup-credit methodology.
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ lastUpdated: 2026-09-03
|
|||
|
||||
## TL;DR — how much free inference does OmniRoute actually aggregate?
|
||||
|
||||
These figures describe separate third-party accounts and eligibility conditions across the catalog. OmniRoute does not grant this budget: you must obtain the required accounts or credentials, connect eligible providers, and respect their limits. Actual usable capacity can be lower, including zero on a fresh installation with no eligible route. Providers marked `tos: avoid` are excluded from automatic routing by default.
|
||||
|
||||
**Checked 2026-10-08:** [Cerebras](https://www.cerebras.ai/pricing) offers a one-time $5 promotional credit requiring a payment method, expiring after 30 days. [Gemini](https://ai.google.dev/gemini-api/docs/rate-limits) publishes project/model/tier rate limits; it remains outside the quantified monthly headline.
|
||||
|
||||
| Metric | Tokens / month | Meaning |
|
||||
| ------------------------------------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Documented recurring grant (steady)** | **~1.62B** | Free-tier **pools** (per-model catalog), each shared pool counted **once**. The live source behind `/api/free-tier/summary` and the dashboard's Free-Tier Budget page. **Use this number.** |
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ export const FREE_TIER_TOS: Record<string, TosVerdict> = {
|
|||
opencode: "avoid",
|
||||
"duckduckgo-web": "avoid",
|
||||
agy: "avoid",
|
||||
antigravity: "avoid", // Both registered IDs use the same Antigravity integration.
|
||||
kiro: "avoid",
|
||||
"amazon-q": "avoid",
|
||||
"muse-spark-web": "avoid",
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ import {
|
|||
grantsFreeAccess,
|
||||
type FreeModelBudget,
|
||||
} from "@omniroute/open-sse/config/freeModelCatalog.ts";
|
||||
import { FREE_TIER_TOS } from "@omniroute/open-sse/config/freeTierCatalog.ts";
|
||||
import { recordAutoExclusion } from "./autoEvaluationTrace";
|
||||
import { SYNTHETIC_NOAUTH_CONNECTION_ID } from "./resilienceCandidateFilter";
|
||||
|
||||
|
|
@ -420,6 +421,8 @@ export function filterTosAvoidCandidates<T extends StrictZeroCostCandidate>(
|
|||
if (!excludeTosAvoid) return pool;
|
||||
return pool.filter((candidate) => {
|
||||
const budgetEntry = findBudgetEntry(candidate, catalog);
|
||||
return budgetEntry?.tos !== "avoid";
|
||||
// Newly discovered models still inherit the provider's curated verdict.
|
||||
const tos = budgetEntry?.tos ?? FREE_TIER_TOS[candidate.provider];
|
||||
return tos !== "avoid";
|
||||
});
|
||||
}
|
||||
|
|
|
|||
77
tests/unit/first-run-catalog-15059.test.ts
Normal file
77
tests/unit/first-run-catalog-15059.test.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
const testDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-first-run-15059-"));
|
||||
process.env.DATA_DIR = testDataDir;
|
||||
process.env.OMNIROUTE_PLUGINS_DIR = path.join(testDataDir, "plugins");
|
||||
process.env.NODE_ENV = "test";
|
||||
process.env.API_KEY_SECRET = "synthetic-first-run-15059-secret";
|
||||
|
||||
const core = await import("../../src/lib/db/core.ts");
|
||||
const providersDb = await import("../../src/lib/db/providers.ts");
|
||||
const modelsDb = await import("../../src/lib/db/models.ts");
|
||||
const { updateSettings } = await import("../../src/lib/db/settings.ts");
|
||||
const catalog = await import("../../src/app/api/v1/models/catalog.ts");
|
||||
const { prepareVirtualAutoComboInputs } =
|
||||
await import("../../open-sse/services/autoCombo/virtualFactory.ts");
|
||||
const { filterTosAvoidCandidates } =
|
||||
await import("../../open-sse/services/autoCombo/strictZeroCostFilter.ts");
|
||||
|
||||
test.after(() => {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
||||
});
|
||||
|
||||
test("fresh auto pool excludes provider-wide ToS-avoid models missing from the budget catalog", async () => {
|
||||
const prepared = await prepareVirtualAutoComboInputs();
|
||||
assert.equal(
|
||||
prepared.regularCandidates.some((row) => row.provider === "opencode"),
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
test("provider ToS verdict covers a newly discovered model absent from the budget catalog", () => {
|
||||
const pool = [{ provider: "opencode", model: "new-uncataloged-model", connectionId: "noauth" }];
|
||||
assert.deepEqual(filterTosAvoidCandidates(pool, true, []), []);
|
||||
});
|
||||
|
||||
test("explicit ToS filter opt-out preserves the original candidate", () => {
|
||||
const pool = [{ provider: "opencode", model: "new-uncataloged-model", connectionId: "noauth" }];
|
||||
assert.equal(filterTosAvoidCandidates(pool, false, []), pool);
|
||||
});
|
||||
|
||||
test("missing provider and model verdicts do not invent a ToS restriction", () => {
|
||||
const pool = [{ provider: "synthetic-provider", model: "new-model", connectionId: "noauth" }];
|
||||
assert.deepEqual(filterTosAvoidCandidates(pool, true, []), pool);
|
||||
});
|
||||
|
||||
test("Moonshot live catalog hides phantom static Kimi K3 after a successful sync", async () => {
|
||||
// This assertion concerns provider models, independent of virtual auto generation.
|
||||
await updateSettings({ hideAutoCombos: true });
|
||||
const connection = await providersDb.createProviderConnection({
|
||||
provider: "moonshot",
|
||||
authType: "apikey",
|
||||
name: "Moonshot fixture",
|
||||
apiKey: "synthetic-moonshot-key",
|
||||
isActive: true,
|
||||
testStatus: "active",
|
||||
});
|
||||
assert.equal(typeof connection.id, "string");
|
||||
await modelsDb.replaceSyncedAvailableModelsForConnection("moonshot", connection.id, [
|
||||
{ id: "kimi-k2.7-code", name: "Kimi K2.7 Code", source: "imported" },
|
||||
{ id: "kimi-k2.6", name: "Kimi K2.6", source: "imported" },
|
||||
]);
|
||||
const response = await catalog.getUnifiedModelsResponse(
|
||||
new Request("http://localhost/api/v1/models")
|
||||
);
|
||||
const body: { data: { id: string }[] } = await response.json();
|
||||
assert.equal(response.status, 200, JSON.stringify(body));
|
||||
const ids = new Set(body.data.map((model) => model.id));
|
||||
assert.ok(ids.has("moonshot/kimi-k2.7-code"));
|
||||
assert.ok(ids.has("moonshot/kimi-k2.6"));
|
||||
assert.equal(ids.has("moonshot/kimi-k3"), false);
|
||||
assert.equal(ids.has("moonshot/kimi-k3-256k"), false);
|
||||
});
|
||||
43
tests/unit/tos-provider-alias-15059.test.ts
Normal file
43
tests/unit/tos-provider-alias-15059.test.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
const testDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-tos-alias-15059-"));
|
||||
process.env.DATA_DIR = testDataDir;
|
||||
process.env.OMNIROUTE_PLUGINS_DIR = path.join(testDataDir, "plugins");
|
||||
process.env.NODE_ENV = "test";
|
||||
process.env.API_KEY_SECRET = "synthetic-tos-alias-15059-secret";
|
||||
|
||||
const { filterTosAvoidCandidates } =
|
||||
await import("../../open-sse/services/autoCombo/strictZeroCostFilter.ts");
|
||||
const { FREE_MODEL_BUDGETS } = await import("../../open-sse/config/freeModelCatalog.ts");
|
||||
|
||||
test.after(() => {
|
||||
fs.rmSync(testDataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
||||
});
|
||||
|
||||
test("canonical Antigravity has the same ToS restriction as the separately registered agy ID", () => {
|
||||
const pool = [{ provider: "antigravity", model: "new-model", connectionId: "connection-a" }];
|
||||
assert.deepEqual(filterTosAvoidCandidates(pool, true, []), []);
|
||||
assert.deepEqual(filterTosAvoidCandidates([{ ...pool[0], provider: "agy" }], true, []), []);
|
||||
});
|
||||
|
||||
test("an explicit opt-out also preserves the canonical Antigravity provider", () => {
|
||||
const pool = [{ provider: "antigravity", model: "new-model", connectionId: "connection-a" }];
|
||||
assert.equal(filterTosAvoidCandidates(pool, false, []), pool);
|
||||
});
|
||||
|
||||
test("a specific model verdict retains precedence over the provider fallback", () => {
|
||||
const pool = [{ provider: "antigravity", model: "new-model", connectionId: "connection-a" }];
|
||||
const catalog = [
|
||||
{
|
||||
...FREE_MODEL_BUDGETS[0],
|
||||
provider: "antigravity",
|
||||
modelId: "new-model",
|
||||
tos: "caution" as const,
|
||||
},
|
||||
];
|
||||
assert.deepEqual(filterTosAvoidCandidates(pool, true, catalog), pool);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue