Remove/mimocode sunset provider (#10186)
* remove: drop sunset MiMoCode provider from model catalog * remove: drop sunset MiMoCode provider from model catalog (shared.ts) Remove unused imports, types, and comments from shared.ts. * remove: MiMoCode provider (Xiaomi sunset) — executor, registry, no-auth config, icon, tests * refactor(providers): finish MiMoCode removal — sweep remaining no-auth references Drop the leftover mimocode entries from the no-auth provider controls, the translate-path snapshot, the eslint suppressions, and the #3061 auth-loop test. Re-point the fingerprint-pin (#6696) and proxy-noauth (#6272) tests at opencode, which exercises the same fingerprint path, so the removal does not break runtime behavior. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * docs(providers): reconcile provider/executor counts after MiMoCode sunset The base's parallel doc-count sync (#10433) pinned 340 providers / 101 executors. With mimocode removed, live code has 339 providers and 100 executors; refresh the user-facing counts (package.json description, llm.txt, README/AGENTS, i18n llm.txt, provider reference, diagrams) so the check-docs-counts STRICT gate stays green. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> * test(providers): fix orphaned mimocode references after MiMoCode sunset The sunset removed mimocode/mcode from the free-onboarding candidates and from FINGERPRINT_PROVIDERS, but two tests still referenced them: - free-provider-onboarding-setup: the mimocode->theoldllm substitution introduced duplicate 'opencode' rows (impossible given the request-set dedupe) and the wrong display name; align expectations with the actual {opencode, theoldllm} dedupe behavior and 'The Old LLM (Free)' name. - combo-system-prompt-templates-5501: resolveTargetFingerprint tested with provider 'mcode', which is no longer a fingerprint provider; point it at the remaining fingerprint provider 'opencode'. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> --------- Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> Co-authored-by: Tushar49 <Tushar49@users.noreply.github.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com> Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
@@ -46,7 +46,7 @@ Repository map and Reference Documentation sections below.
|
||||
|
||||
## Project at a Glance
|
||||
|
||||
**OmniRoute** — unified AI proxy/router. One endpoint, 341 LLM providers, auto-fallback.
|
||||
**OmniRoute** — unified AI proxy/router. One endpoint, 340 LLM providers, auto-fallback.
|
||||
|
||||
| Layer | Location | Purpose |
|
||||
| ------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
16
README.md
@@ -7,7 +7,7 @@
|
||||
|
||||
# 🚀 OmniRoute — The Free AI Gateway
|
||||
|
||||
<img src="./docs/diagrams/readme-hero.svg" width="100%" alt="OmniRoute — Never stop coding. Every AI tool → 341 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot & Antigravity into FREE Claude / GPT / Gemini with auto-fallback. RTK + Caveman stacked compression saves 15–95% tokens (~89% avg) — never hit limits. 341 AI providers · 90+ free tiers · ~1.51B free tokens/mo · 19 routing strategies · $0 to start."/>
|
||||
<img src="./docs/diagrams/readme-hero.svg" width="100%" alt="OmniRoute — Never stop coding. Every AI tool → 340 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot & Antigravity into FREE Claude / GPT / Gemini with auto-fallback. RTK + Caveman stacked compression saves 15–95% tokens (~89% avg) — never hit limits. 340 AI providers · 90+ free tiers · ~1.51B free tokens/mo · 19 routing strategies · $0 to start."/>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
| | v3.8.49 | **v3.8.50** | `v3.8.51+` |
|
||||
| ------------------------- | :-----: | :---------: | :---------: |
|
||||
| 🌐 Providers | 290 | **341** | more queued |
|
||||
| 🌐 Providers | 290 | **340** | more queued |
|
||||
| 🧠 Documented models | 1185 | **1202** | — |
|
||||
| 🖼️ Modality Bridge | — | 🆕 vision | video |
|
||||
| 📡 Radar free catalog | — | 🆕 opt-in | — |
|
||||
@@ -101,7 +101,7 @@
|
||||
<tr>
|
||||
<td align="right"><b>⚙️ Features</b></td>
|
||||
<td align="center"><a href="#-combos--the-flagship">🎯 Combos</a></td>
|
||||
<td align="center"><a href="#-341-ai-providers--90-free">🌐 Providers</a></td>
|
||||
<td align="center"><a href="#-340-ai-providers--90-free">🌐 Providers</a></td>
|
||||
<td align="center"><a href="#-full-cli--a2a--mcp">🔌 CLI & MCP</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -210,7 +210,7 @@ curl http://localhost:20128/v1/chat/completions \
|
||||
|
||||
</div>
|
||||
|
||||
<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint. 341 providers. Never stop building — OmniRoute picks the cheapest one that works. Six pillars: Never hit limits (auto-fallback across 341 providers in milliseconds, zero downtime) · Save up to 95% tokens (RTK + Caveman stacked compression cuts 15–95%, ~89% avg on tool-heavy sessions) · $0 to start (90+ free tiers, 56 free forever — no card needed) · Every tool works (33 coding agents through one config) · One endpoint (OpenAI ↔ Claude ↔ Gemini ↔ Responses API at /v1) · Production-grade (circuit breakers, TLS stealth, MCP 109 tools, A2A, memory, guardrails, evals — 25,000+ tests)."/>
|
||||
<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint. 340 providers. Never stop building — OmniRoute picks the cheapest one that works. Six pillars: Never hit limits (auto-fallback across 340 providers in milliseconds, zero downtime) · Save up to 95% tokens (RTK + Caveman stacked compression cuts 15–95%, ~89% avg on tool-heavy sessions) · $0 to start (90+ free tiers, 56 free forever — no card needed) · Every tool works (33 coding agents through one config) · One endpoint (OpenAI ↔ Claude ↔ Gemini ↔ Responses API at /v1) · Production-grade (circuit breakers, TLS stealth, MCP 109 tools, A2A, memory, guardrails, evals — 25,000+ tests)."/>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
@@ -461,7 +461,7 @@ All **19** strategies — mix & match per combo step:
|
||||
|
||||
</div>
|
||||
|
||||
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — comparison table vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 341 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, built-in MCP server with 109 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA, 43 i18n UI locales, 100% MIT self-hosted. OmniRoute is the only one with the full set; competitors show a mix of checks, partials and crosses. Verified from each project's docs."/>
|
||||
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — comparison table vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 340 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, built-in MCP server with 109 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA, 43 i18n UI locales, 100% MIT self-hosted. OmniRoute is the only one with the full set; competitors show a mix of checks, partials and crosses. Verified from each project's docs."/>
|
||||
|
||||
<sub>📊 Full methodology & per-feature detail vs 9router, OpenRouter, CLIProxyAPI & LiteLLM → [`docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md`](docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md)</sub>
|
||||
|
||||
@@ -559,7 +559,7 @@ the current catalog at **[radar.omniroute.online/planos](https://radar.omniroute
|
||||
- **🖼️ New endpoints** — `/v1/ocr` (Mistral OCR) and `/v1/audio/translations` (Whisper-style) round out the media surface. → [API Reference](docs/reference/API_REFERENCE.md)
|
||||
- **🎨 Image / video / audio generation** — one API for media: xAI Grok Imagine & Novita AI video, ComfyUI, Freepik, Adobe Firefly, Microsoft Designer, Google Imagen, Segmind, EdgeTTS. → [API Reference](docs/reference/API_REFERENCE.md)
|
||||
- **🌍 Deployment & ops** — reverse-proxy `basePath`, browser-language auto-detect, per-key device tracking, root-less MITM trust, zh-TW localization. → [Environment](docs/reference/ENVIRONMENT.md)
|
||||
- **🤝 More providers & agents** — Cursor Cloud Agent, Grok Build (xAI) with browser + OAuth login, Ollama first-class card, Claude Opus 5 & Sonnet 5, Kimi official partnership (Code/Web/Moonshot), Zed, Requesty, SenseNova, Yuanbao, Agnes AI… and a refreshed **341-provider catalog**. → [Providers](docs/reference/PROVIDER_REFERENCE.md)
|
||||
- **🤝 More providers & agents** — Cursor Cloud Agent, Grok Build (xAI) with browser + OAuth login, Ollama first-class card, Claude Opus 5 & Sonnet 5, Kimi official partnership (Code/Web/Moonshot), Zed, Requesty, SenseNova, Yuanbao, Agnes AI… and a refreshed **340-provider catalog**. → [Providers](docs/reference/PROVIDER_REFERENCE.md)
|
||||
- **📡 Routing transparency** — every response carries an `X-OmniRoute-Decision` header naming the strategy/provider/latency that served it, a new `cache-optimized` combo strategy + Auto-Combo `cacheAffinity` factor route repeat requests back to the connection holding the cached prefix, and a read-only `/v1/auto-combo/{channel}/candidates` endpoint exposes an `auto/*` channel's live candidate pool. → [Auto-Combo](docs/routing/AUTO-COMBO.md)
|
||||
- **⚡ Local performance & infra** — one-click local Redis, Cloudflare Workers / Deno Deploy relay deployers, Bifrost & Mux as supervised embedded services. → [Embedded Services](docs/frameworks/EMBEDDED-SERVICES.md)
|
||||
|
||||
@@ -620,11 +620,11 @@ the current catalog at **[radar.omniroute.online/planos](https://radar.omniroute
|
||||
|
||||
<div align="center">
|
||||
|
||||
## 🌐 341 AI Providers — 90+ Free
|
||||
## 🌐 340 AI Providers — 90+ Free
|
||||
|
||||
</div>
|
||||
|
||||
> The most complete catalog of any open-source router: **341 providers**, **90+ with a free tier**, **56 free forever**.
|
||||
> The most complete catalog of any open-source router: **340 providers**, **90+ with a free tier**, **56 free forever**.
|
||||
|
||||
<div align="center">
|
||||
|
||||
|
||||
@@ -1491,11 +1491,6 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"tests/integration/mimocode-proxy.integration.test.ts": {
|
||||
"@typescript-eslint/no-explicit-any": {
|
||||
"count": 13
|
||||
}
|
||||
},
|
||||
"tests/integration/obsidian-plugin-e2e.test.ts": {
|
||||
"@typescript-eslint/no-explicit-any": {
|
||||
"count": 12
|
||||
@@ -2559,11 +2554,6 @@
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"tests/unit/mimocode-executor.test.ts": {
|
||||
"@typescript-eslint/no-explicit-any": {
|
||||
"count": 58
|
||||
}
|
||||
},
|
||||
"tests/unit/minimax-tts-1043.test.ts": {
|
||||
"@typescript-eslint/no-explicit-any": {
|
||||
"count": 6
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<svg viewBox="0 0 1200 350" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Animated terminal demoing the OmniRoute CLI: omniroute providers list (341 providers registered, anthropic, codex, glm, kimi shown active), omniroute combo list (always-on priority, cost-saver, fusion-panel, context-relay) and omniroute health (healthy, 18412 requests in 24h, p95 412ms, circuit breakers 24 closed, 1 half-open, 0 open), cycling over the 80+ command surface: providers, oauth, keys, combo, nodes, models, cache, compression, cost, usage, quota, health, resilience, telemetry, logs, audit, mcp, a2a, cloud, memory, skills, eval, doctor, repl, tunnel, backup, sync, webhooks, policy, pricing, translator, simulate and more.">
|
||||
<svg viewBox="0 0 1200 350" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Animated terminal demoing the OmniRoute CLI: omniroute providers list (340 providers registered, anthropic, codex, glm, kimi shown active), omniroute combo list (always-on priority, cost-saver, fusion-panel, context-relay) and omniroute health (healthy, 18412 requests in 24h, p95 412ms, circuit breakers 24 closed, 1 half-open, 0 open), cycling over the 80+ command surface: providers, oauth, keys, combo, nodes, models, cache, compression, cost, usage, quota, health, resilience, telemetry, logs, audit, mcp, a2a, cloud, memory, skills, eval, doctor, repl, tunnel, backup, sync, webhooks, policy, pricing, translator, simulate and more.">
|
||||
<desc>Compact animated terminal cycling three real OmniRoute CLI commands with a typewriter effect and a scrolling subcommand ticker; the first frame shows the completed providers-list screen.</desc>
|
||||
<defs><clipPath id="tickerClip"><rect x="12" y="304" width="1176" height="40"/></clipPath><clipPath id="tw0"><rect x="64" y="46" height="26" width="0"><animate attributeName="width" calcMode="discrete" values="0;31;61;92;122;153;184;214;245;245" keyTimes="0;0.012;0.018;0.024;0.030;0.036;0.042;0.048;0.054;1" dur="18s" repeatCount="indefinite"/></rect></clipPath><clipPath id="tw1"><rect x="64" y="46" height="26" width="0"><animate attributeName="width" calcMode="discrete" values="0;26;51;76;102;128;153;178;204;204" keyTimes="0;0.345;0.351;0.357;0.363;0.369;0.375;0.381;0.387;1" dur="18s" repeatCount="indefinite"/></rect></clipPath><clipPath id="tw2"><rect x="64" y="46" height="26" width="0"><animate attributeName="width" calcMode="discrete" values="0;20;41;61;82;102;122;143;163;163" keyTimes="0;0.678;0.684;0.690;0.696;0.702;0.708;0.714;0.720;1" dur="18s" repeatCount="indefinite"/></rect></clipPath></defs>
|
||||
<rect width="1200" height="350" fill="#0d1117"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg viewBox="0 0 1200 780" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Comparison table: OmniRoute versus 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute is the only one with the full set: 341 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, a built-in MCP server with 109 tools, A2A protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, desktop/Termux/PWA, 43 UI locales and 100% MIT self-hosted. 9router has free providers, RTK compression and translation but no MCP, A2A, memory, guardrails, cloud agents or stealth. OpenRouter is a hosted SaaS with 400+ models, guardrails and a hosted MCP but is not self-hosted and lacks A2A, memory, cloud agents and stealth. CLIProxyAPI is a light OAuth proxy with two routing strategies. LiteLLM has 100+ providers, A2A and extensive guardrails but no memory, compression, free tier, stealth or cloud agents.">
|
||||
<svg viewBox="0 0 1200 780" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Comparison table: OmniRoute versus 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute is the only one with the full set: 340 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, a built-in MCP server with 109 tools, A2A protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, desktop/Termux/PWA, 43 UI locales and 100% MIT self-hosted. 9router has free providers, RTK compression and translation but no MCP, A2A, memory, guardrails, cloud agents or stealth. OpenRouter is a hosted SaaS with 400+ models, guardrails and a hosted MCP but is not self-hosted and lacks A2A, memory, cloud agents and stealth. CLIProxyAPI is a light OAuth proxy with two routing strategies. LiteLLM has 100+ providers, A2A and extensive guardrails but no memory, compression, free tier, stealth or cloud agents.">
|
||||
<desc>Static-header comparison table where each capability row fades in top to bottom; the OmniRoute column is highlighted and shows a check or a leading value in every row, while competitors show a mix of checks, partials and crosses.</desc>
|
||||
<defs>
|
||||
<pattern id="gC" width="32" height="32" patternUnits="userSpaceOnUse"><path d="M 32 0 L 0 0 0 32" fill="none" stroke="#ffffff" stroke-opacity="0.05" stroke-width="1"/></pattern>
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg viewBox="0 0 1200 540" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The OmniRoute promise: one endpoint, 341 providers — never stop building, OmniRoute picks the cheapest one that works. Six pillars. Never hit limits: auto-fallback across 341 providers in milliseconds, quota out means the next provider takes over with zero downtime. Save up to 95 percent of tokens: RTK plus Caveman stacked compression cuts 15 to 95 percent of eligible tokens, about 89 percent average on tool-heavy sessions. Zero dollars to start: 90+ providers with a free tier, 56 free forever — Qoder, Pollinations, Cloudflare, SiliconFlow — no card needed. Every tool works: 33 coding agents including Claude Code, Codex, Cursor, Cline, Copilot and Antigravity through one config. One endpoint: OpenAI, Claude, Gemini and Responses API translation — point any tool at /v1 and it just works. Production-grade: circuit breakers, TLS stealth, MCP with 109 tools, A2A, memory, guardrails, evals — 25,000+ tests.">
|
||||
<svg viewBox="0 0 1200 540" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The OmniRoute promise: one endpoint, 340 providers — never stop building, OmniRoute picks the cheapest one that works. Six pillars. Never hit limits: auto-fallback across 340 providers in milliseconds, quota out means the next provider takes over with zero downtime. Save up to 95 percent of tokens: RTK plus Caveman stacked compression cuts 15 to 95 percent of eligible tokens, about 89 percent average on tool-heavy sessions. Zero dollars to start: 90+ providers with a free tier, 56 free forever — Qoder, Pollinations, Cloudflare, SiliconFlow — no card needed. Every tool works: 33 coding agents including Claude Code, Codex, Cursor, Cline, Copilot and Antigravity through one config. One endpoint: OpenAI, Claude, Gemini and Responses API translation — point any tool at /v1 and it just works. Production-grade: circuit breakers, TLS stealth, MCP with 109 tools, A2A, memory, guardrails, evals — 25,000+ tests.">
|
||||
<desc>Animated promise card: six pillar tiles fade in in reading order, then a soft colored border highlight sweeps from tile to tile in a continuous cycle.</desc>
|
||||
<defs>
|
||||
<pattern id="gridPaperP" width="32" height="32" patternUnits="userSpaceOnUse">
|
||||
@@ -21,7 +21,7 @@
|
||||
<line x1="150" y1="53" x2="1160" y2="53" stroke="#232b38" stroke-width="1.5"/>
|
||||
</g>
|
||||
<g>
|
||||
<text x="40" y="100" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="23" font-weight="600" fill="#c9d1d9">One endpoint. <tspan fill="#a78bfa" font-weight="800">341 providers.</tspan> Never stop building — OmniRoute picks <tspan fill="#7ee787" font-weight="700">the cheapest one that works</tspan>.</text>
|
||||
<text x="40" y="100" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="23" font-weight="600" fill="#c9d1d9">One endpoint. <tspan fill="#a78bfa" font-weight="800">340 providers.</tspan> Never stop building — OmniRoute picks <tspan fill="#7ee787" font-weight="700">the cheapest one that works</tspan>.</text>
|
||||
</g>
|
||||
|
||||
<g font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif">
|
||||
@@ -38,7 +38,7 @@
|
||||
<line x1="3.9" y1="3.9" x2="18.1" y2="18.1"/>
|
||||
</g>
|
||||
<text x="102" y="170" font-size="18" font-weight="800" fill="#74b9ff">Never hit limits</text>
|
||||
<text x="66" y="204" font-size="13.5" fill="#a1a1aa">Auto-fallback across 341 providers in</text>
|
||||
<text x="66" y="204" font-size="13.5" fill="#a1a1aa">Auto-fallback across 340 providers in</text>
|
||||
<text x="66" y="226" font-size="13.5" fill="#a1a1aa">milliseconds. Quota out? The next provider</text>
|
||||
<text x="66" y="248" font-size="13.5" fill="#a1a1aa">takes over — zero downtime.</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg viewBox="0 0 1200 548" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="OmniRoute hero: Never stop coding. Every AI tool to 341 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot and Antigravity into free Claude, GPT and Gemini with auto-fallback. RTK + Caveman stacked compression saves 15 to 95 percent of tokens — about 89 percent average on tool-heavy sessions — so you never hit limits. Stats: 341 AI providers, 90+ free tiers, about 1.51B free tokens per month, 15 to 95 percent token savings, 19 routing strategies, zero dollars to start.">
|
||||
<svg viewBox="0 0 1200 548" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="OmniRoute hero: Never stop coding. Every AI tool to 340 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot and Antigravity into free Claude, GPT and Gemini with auto-fallback. RTK + Caveman stacked compression saves 15 to 95 percent of tokens — about 89 percent average on tool-heavy sessions — so you never hit limits. Stats: 340 AI providers, 90+ free tiers, about 1.51B free tokens per month, 15 to 95 percent token savings, 19 routing strategies, zero dollars to start.">
|
||||
<desc>Animated hero card: a pulse travels the divider line and a compression bar demo repeatedly shrinks a prompt by up to 95 percent; all headline content is static and readable on the first frame.</desc>
|
||||
<defs>
|
||||
<pattern id="gridPaperH" width="32" height="32" patternUnits="userSpaceOnUse">
|
||||
@@ -28,7 +28,7 @@
|
||||
<text x="48" y="138" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="60" font-weight="800" fill="#e9edf3">Never stop coding<tspan fill="#a855f7">.</tspan></text>
|
||||
|
||||
<!-- subheadline -->
|
||||
<text x="48" y="184" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="25" font-weight="600" fill="#c9d1d9">Every AI tool → <tspan fill="#a78bfa" font-weight="800">341 providers</tspan> — <tspan fill="#7ee787" font-weight="800">90+ free</tspan> — through one endpoint.</text>
|
||||
<text x="48" y="184" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="25" font-weight="600" fill="#c9d1d9">Every AI tool → <tspan fill="#a78bfa" font-weight="800">340 providers</tspan> — <tspan fill="#7ee787" font-weight="800">90+ free</tspan> — through one endpoint.</text>
|
||||
|
||||
<!-- plug line -->
|
||||
<text x="48" y="222" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="16.5" fill="#a1a1aa">Claude Code · Codex · Cursor · Cline · Copilot · Antigravity  →  <tspan fill="#7ee787" font-weight="700">FREE</tspan> Claude / GPT / Gemini · auto-fallback</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
---
|
||||
title: "Provider Reference"
|
||||
version: 3.8.50
|
||||
lastUpdated: 2026-08-16
|
||||
lastUpdated: 2026-08-18
|
||||
---
|
||||
|
||||
# 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-16
|
||||
> **Last generated:** 2026-08-18
|
||||
|
||||
Total providers: **341**. See category breakdown below.
|
||||
Total providers: **340**. See category breakdown below.
|
||||
|
||||
## Categories
|
||||
|
||||
@@ -34,7 +34,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
|
||||
|
||||
---
|
||||
|
||||
## No-auth Providers (no key required) (11)
|
||||
## No-auth Providers (no key required) (10)
|
||||
|
||||
| ID | Alias | Name | Tags | Website | Notes | Tool calling |
|
||||
|----|-------|------|------|---------|-------|--------------|
|
||||
@@ -44,7 +44,6 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
|
||||
| `devin-cli-agentic` | `dva` | Devin CLI Agentic Bridge | No-auth | [link](https://docs.devin.ai/work-with-devin/devin-cli) | Authentication is owned by the official Devin CLI in its isolated bridge volume. | emulated |
|
||||
| `duckduckgo-web` | `ddgw` | DuckDuckGo AI Chat | No-auth | [link](https://duckduckgo.com/duckchat) | No credentials required — DuckDuckGo AI Chat is anonymous and free. | emulated |
|
||||
| `felo-web` | `felo` | Felo | No-auth | [link](https://felo.ai) | No credentials required — Felo is a free, no-signup chat/search aggregator. | — |
|
||||
| `mimocode` | `mcode` | MiMoCode (Free) | No-auth | [link](https://mimo.mi.com) | No API key required. The executor auto-generates JWT tokens via device fingerprint bootstrap. | — |
|
||||
| `opencode` | `oc` | OpenCode Free | No-auth | [link](https://opencode.ai) | No API key required — uses OpenCode's public free endpoint. | — |
|
||||
| `theoldllm` | `tllm` | The Old LLM (Free) | No-auth | [link](https://theoldllm.vercel.app) | No credentials required. The executor auto-generates access tokens via an embedded Playwright browser instance. | — |
|
||||
| `veoaifree-web` | `veo-free` | Veo AI Free | No-auth, video | [link](https://veoaifree.com) | No auth required. Rate limited to 6 requests/hour per IP. | — |
|
||||
@@ -429,7 +428,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
|
||||
|
||||
- Catalog: [`src/shared/constants/providers.ts`](../../src/shared/constants/providers.ts)
|
||||
- Registry (per-model details): [`open-sse/config/providerRegistry.ts`](../../open-sse/config/providerRegistry.ts)
|
||||
- Executors: [`open-sse/executors/`](../../open-sse/executors/) (104 implementations)
|
||||
- Executors: [`open-sse/executors/`](../../open-sse/executors/) (103 implementations)
|
||||
- Translators: [`open-sse/translator/`](../../open-sse/translator/)
|
||||
|
||||
## See Also
|
||||
|
||||
8
llm.txt
@@ -1,6 +1,6 @@
|
||||
# OmniRoute
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 340 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -165,7 +165,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ └── manager.ts # MITM proxy manager
|
||||
│ ├── shared/ # Shared utilities, components, and constants
|
||||
│ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.)
|
||||
│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── constants/ # Provider definitions (340), model lists, pricing, routing strategies, MCP scopes
|
||||
│ │ ├── contracts/ # Shared API contracts
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── middleware/ # Shared middleware utilities
|
||||
@@ -277,7 +277,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
## Key Features (v3.8.50)
|
||||
|
||||
### Core Proxy
|
||||
- **341 AI providers** with automatic format translation
|
||||
- **340 AI providers** with automatic format translation
|
||||
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
|
||||
- **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline
|
||||
- **4-tier fallback**: Subscription → API Key → Cheap → Free
|
||||
@@ -475,7 +475,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
|
||||
## v3.8.x Highlights
|
||||
|
||||
- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **340-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
|
||||
@@ -3,7 +3,6 @@ import { unorouterProvider } from "./registry/unorouter/index.ts";
|
||||
|
||||
import { aimlapiProvider } from "./registry/aimlapi/index.ts";
|
||||
import { byteplusProvider } from "./registry/byteplus/index.ts";
|
||||
import { mimocodeProvider } from "./registry/mimocode/index.ts";
|
||||
import { ollama_cloudProvider } from "./registry/ollama-cloud/index.ts";
|
||||
import { syntheticProvider } from "./registry/synthetic/index.ts";
|
||||
import { ideogramProvider } from "./registry/ideogram/index.ts";
|
||||
@@ -470,7 +469,6 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
venice: veniceProvider,
|
||||
kiro: kiroProvider,
|
||||
byteplus: byteplusProvider,
|
||||
mimocode: mimocodeProvider,
|
||||
wafer: waferProvider,
|
||||
openadapter: openadapterProvider,
|
||||
dit: ditProvider,
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import type { RegistryEntry } from "../../shared.ts";
|
||||
import { CHAT_OPENAI_COMPAT_MODELS } from "../../shared.ts";
|
||||
|
||||
// Mimocode (Xiaomi MiMo free OpenAI-compatible gateway) — no-auth, custom executor.
|
||||
// Re-added after the registry modularization (#3993) dropped it; restores #3837.
|
||||
export const mimocodeProvider: RegistryEntry = {
|
||||
id: "mimocode",
|
||||
alias: "mcode",
|
||||
format: "openai",
|
||||
executor: "mimocode",
|
||||
baseUrl: "https://api.xiaomimimo.com",
|
||||
chatPath: "/api/free-ai/openai/chat",
|
||||
authType: "none",
|
||||
authHeader: "none",
|
||||
models: CHAT_OPENAI_COMPAT_MODELS["mimocode"],
|
||||
};
|
||||
@@ -663,12 +663,6 @@ export const CHAT_OPENAI_COMPAT_MODELS: Record<string, RegistryModel[]> = {
|
||||
"mistralai/Mistral-7B-Instruct-v0.3",
|
||||
"Qwen/Qwen2.5-72B-Instruct",
|
||||
]),
|
||||
// Restored after the registry modularization (#3993) dropped the mimocode key
|
||||
// referenced by the mimocode provider plugin. Source of truth: pre-#3993
|
||||
// providerRegistry.ts (commit 1ed01dd90^).
|
||||
mimocode: [
|
||||
{ id: "mimo-auto", name: "MiMo Auto", contextLength: 1000000, maxOutputTokens: 128000 },
|
||||
],
|
||||
};
|
||||
|
||||
export function mapStainlessOs() {
|
||||
|
||||
@@ -68,7 +68,6 @@ import { MoonshotExecutor } from "./moonshot.ts";
|
||||
import { TheOldLlmExecutor } from "./theoldllm.ts";
|
||||
import { ChipotleExecutor } from "./chipotle.ts";
|
||||
import { LMArenaExecutor } from "./lmarena.ts";
|
||||
import { MimocodeExecutor } from "./mimocode.ts";
|
||||
import { GrokCliExecutor } from "./grok-cli.ts";
|
||||
import { CodeBuddyCnExecutor } from "./codebuddy-cn.ts";
|
||||
import { ZenmuxFreeExecutor } from "./zenmux-free.ts";
|
||||
@@ -200,8 +199,6 @@ const executors = {
|
||||
pepper: new ChipotleExecutor(), // Alias
|
||||
lmarena: new LMArenaExecutor(),
|
||||
lma: new LMArenaExecutor(), // Alias
|
||||
mimocode: new MimocodeExecutor(),
|
||||
mcode: new MimocodeExecutor(), // Alias
|
||||
"grok-cli": new GrokCliExecutor(),
|
||||
gc: new GrokCliExecutor(), // Alias
|
||||
"codebuddy-cn": new CodeBuddyCnExecutor(),
|
||||
@@ -323,7 +320,6 @@ export { HailuoWebExecutor } from "./hailuo-web.ts";
|
||||
export { TheOldLlmExecutor } from "./theoldllm.ts";
|
||||
export { ChipotleExecutor } from "./chipotle.ts";
|
||||
export { LMArenaExecutor } from "./lmarena.ts";
|
||||
export { MimocodeExecutor } from "./mimocode.ts";
|
||||
export { GrokCliExecutor } from "./grok-cli.ts";
|
||||
export { CodeBuddyCnExecutor } from "./codebuddy-cn.ts";
|
||||
export { ZenmuxFreeExecutor } from "./zenmux-free.ts";
|
||||
|
||||
@@ -1,711 +0,0 @@
|
||||
/**
|
||||
* MiMoCode Executor — Free-tier Xiaomi MiMo models via bootstrap JWT auth.
|
||||
*
|
||||
* Implements the auth flow from the official MiMo-Code repository:
|
||||
* https://github.com/XiaomiMiMo/MiMo-Code/blob/main/packages/opencode/src/plugin/mimo-free.ts
|
||||
*
|
||||
* 1. Generate device fingerprint from hostname + OS + arch + CPU + username
|
||||
* 2. POST /api/free-ai/bootstrap with fingerprint → JWT
|
||||
* 3. Use JWT as Bearer token for chat requests
|
||||
* 4. Custom endpoint: /api/free-ai/openai/chat (not /v1/chat/completions)
|
||||
* 5. Custom header: X-Mimo-Source: mimocode-cli-free
|
||||
*
|
||||
* Only the "mimo-auto" model is supported (1M context, 128K output).
|
||||
* Supports multiple accounts: N fingerprints → N JWTs → round-robin with cooldown.
|
||||
* On 429 — or a 400 carrying MiMoCode's rate-limit text — account enters cooldown
|
||||
* (exponential backoff) and the next account is tried. On 401/403, JWT is
|
||||
* re-bootstrapped. Any other 400 is a genuinely malformed request (#2101): it fails
|
||||
* fast on the current account instead of being retried identically on every
|
||||
* account, which would waste N round-trips, cooldown every account, and hide the
|
||||
* real upstream diagnostic behind a generic "all accounts exhausted" error (#4976).
|
||||
*/
|
||||
|
||||
import * as crypto from "node:crypto";
|
||||
import * as os from "node:os";
|
||||
import { BaseExecutor, type ExecuteInput, type ProviderCredentials } from "./base.ts";
|
||||
import { createProxyDispatcher } from "../utils/proxyDispatcher.ts";
|
||||
import { RATE_LIMIT_TEXT_PATTERNS } from "../services/accountFallback.ts";
|
||||
import { buildErrorBody, sanitizeErrorMessage } from "../utils/error.ts";
|
||||
import { fetch as undiciFetch, type Dispatcher } from "undici";
|
||||
import {
|
||||
type AccountProxyConfig as SharedAccountProxyConfig,
|
||||
type RotatableAccount,
|
||||
pickAccount as pickRotatableAccount,
|
||||
markCooldown as markAccountCooldown,
|
||||
markSuccess as markAccountSuccess,
|
||||
maskAccountId,
|
||||
isNetworkErrorRotatable,
|
||||
} from "./accountRotation.ts";
|
||||
import { isNetworkRotationSharedEgressGuardEnabled } from "@/shared/utils/featureFlags";
|
||||
|
||||
const BOOTSTRAP_PATH = "/api/free-ai/bootstrap";
|
||||
const CHAT_PATH = "/api/free-ai/openai/chat";
|
||||
const JWT_REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
||||
const BOOTSTRAP_TIMEOUT_MS = 15_000;
|
||||
|
||||
const MIMO_SOURCE = "mimocode-cli-free";
|
||||
|
||||
/**
|
||||
* Anti-abuse gate marker required by the Xiaomi free endpoint.
|
||||
*
|
||||
* `/api/free-ai/openai/chat` returns `403 "Illegal access"` unless the request body
|
||||
* contains a recognized MiMoCode prompt signature as a substring inside a `system`-role
|
||||
* message (verified empirically — headers, fingerprint, and JWT are not what is checked).
|
||||
* This is the canonical MiMoCode agent opener the official CLI sends, and it is on the
|
||||
* upstream allowlist. We inject it as a leading system message so user requests pass the
|
||||
* gate. The string MUST stay byte-for-byte identical — the check is case-sensitive and
|
||||
* truncations are rejected.
|
||||
*/
|
||||
export const MIMO_SYSTEM_MARKER =
|
||||
"You are MiMoCode, an interactive CLI tool that helps users with software engineering tasks.";
|
||||
|
||||
/**
|
||||
* Ensure the outgoing body carries the MiMoCode anti-abuse marker in a system message.
|
||||
* Idempotent: if any system message already contains the marker, the body is returned
|
||||
* unchanged. Bodies without a `messages` array are left untouched.
|
||||
*/
|
||||
function injectSystemMarker(body: Record<string, unknown>): Record<string, unknown> {
|
||||
const messages = body.messages;
|
||||
if (!Array.isArray(messages)) return body;
|
||||
|
||||
const hasMarker = messages.some(
|
||||
(m) =>
|
||||
m != null &&
|
||||
typeof m === "object" &&
|
||||
(m as { role?: unknown }).role === "system" &&
|
||||
typeof (m as { content?: unknown }).content === "string" &&
|
||||
(m as { content: string }).content.includes(MIMO_SYSTEM_MARKER)
|
||||
);
|
||||
if (hasMarker) return body;
|
||||
|
||||
return { ...body, messages: [{ role: "system", content: MIMO_SYSTEM_MARKER }, ...messages] };
|
||||
}
|
||||
|
||||
const USER_AGENTS = [
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36",
|
||||
];
|
||||
|
||||
// ── Account State ──────────────────────────────────────────────────────────
|
||||
|
||||
/** Per-account proxy configuration, passed through providerSpecificData.accountProxies. */
|
||||
export type AccountProxyConfig = SharedAccountProxyConfig;
|
||||
|
||||
interface AccountState extends RotatableAccount {
|
||||
fingerprint: string;
|
||||
jwt: string;
|
||||
expiresAt: number;
|
||||
/**
|
||||
* #3837/#5521: the account's resolved proxy, or `null` when none is configured.
|
||||
* Always present (never `undefined`) so callers can read `acct.proxy` directly —
|
||||
* syncAccountsFromCredentials() writes it on every account on every sync.
|
||||
*/
|
||||
proxy: AccountProxyConfig["proxy"];
|
||||
}
|
||||
|
||||
function parseJwtExp(jwt: string): number {
|
||||
try {
|
||||
const parts = jwt.split(".");
|
||||
if (parts.length < 2) return Date.now() + 50 * 60 * 1000;
|
||||
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
||||
return (payload.exp ?? Math.floor(Date.now() / 1000) + 3000) * 1000;
|
||||
} catch {
|
||||
return Date.now() + 50 * 60 * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
function isAccountReady(account: AccountState): boolean {
|
||||
if (account.cooldownUntil > Date.now()) return false;
|
||||
if (account.jwt && account.expiresAt - Date.now() > JWT_REFRESH_BUFFER_MS) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ── Fingerprint Generation ─────────────────────────────────────────────────
|
||||
|
||||
function getCpuModel(): string {
|
||||
try {
|
||||
const cpus = os.cpus();
|
||||
if (cpus.length > 0 && cpus[0].model) return cpus[0].model.trim();
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
return "unknown-cpu";
|
||||
}
|
||||
|
||||
export function generateFingerprint(seed?: string): string {
|
||||
if (seed) return crypto.createHash("sha256").update(seed).digest("hex");
|
||||
const hostname = os.hostname();
|
||||
const platform = os.platform();
|
||||
const arch = os.arch();
|
||||
const cpu = getCpuModel();
|
||||
let username = "unknown-user";
|
||||
try {
|
||||
username = os.userInfo().username;
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
return crypto
|
||||
.createHash("sha256")
|
||||
.update(`${hostname}|${platform}|${arch}|${cpu}|${username}`)
|
||||
.digest("hex");
|
||||
}
|
||||
|
||||
// ── Bootstrap ──────────────────────────────────────────────────────────────
|
||||
|
||||
const bootstrapInflight = new Map<string, Promise<{ jwt: string; expiresAt: number }>>();
|
||||
|
||||
async function bootstrapJwt(
|
||||
baseUrl: string,
|
||||
fingerprint: string,
|
||||
signal?: AbortSignal | null,
|
||||
dispatcher?: Dispatcher
|
||||
): Promise<{ jwt: string; expiresAt: number }> {
|
||||
const existing = bootstrapInflight.get(fingerprint);
|
||||
if (existing) return existing;
|
||||
|
||||
const url = `${baseUrl}${BOOTSTRAP_PATH}`;
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => {
|
||||
const err = new Error(`mimocode bootstrap timeout after ${BOOTSTRAP_TIMEOUT_MS}ms`);
|
||||
err.name = "TimeoutError";
|
||||
controller.abort(err);
|
||||
}, BOOTSTRAP_TIMEOUT_MS);
|
||||
const onSignal = signal ? () => controller.abort(signal.reason) : null;
|
||||
if (signal && onSignal) signal.addEventListener("abort", onSignal, { once: true });
|
||||
|
||||
const promise = (async () => {
|
||||
try {
|
||||
const resp = dispatcher
|
||||
? await undiciFetch(url, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ client: fingerprint }),
|
||||
signal: controller.signal,
|
||||
dispatcher,
|
||||
})
|
||||
: await fetch(url, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ client: fingerprint }),
|
||||
signal: controller.signal,
|
||||
});
|
||||
if (!resp.ok) {
|
||||
const body = await resp.text().catch(() => "");
|
||||
throw new Error(`Bootstrap failed: ${resp.status} ${body.slice(0, 200)}`);
|
||||
}
|
||||
const data = (await resp.json()) as { jwt?: string };
|
||||
if (!data.jwt) throw new Error("Bootstrap response missing jwt field");
|
||||
return { jwt: data.jwt, expiresAt: parseJwtExp(data.jwt) };
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
if (signal && onSignal) signal.removeEventListener("abort", onSignal);
|
||||
bootstrapInflight.delete(fingerprint);
|
||||
}
|
||||
})();
|
||||
|
||||
bootstrapInflight.set(fingerprint, promise);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// ── Model Rewriting ────────────────────────────────────────────────────────
|
||||
|
||||
function rewriteModelName(model: string): string {
|
||||
const idx = model.lastIndexOf("/");
|
||||
return idx >= 0 ? model.slice(idx + 1) : model;
|
||||
}
|
||||
|
||||
// ── Executor ───────────────────────────────────────────────────────────────
|
||||
|
||||
export class MimocodeExecutor extends BaseExecutor {
|
||||
private accounts: AccountState[] = [];
|
||||
// Not `private`: passed as the mutable rotation cursor to the shared
|
||||
// pickAccount() helper, which needs a plain `{ nextAccountIdx }` shape —
|
||||
// TS's private-member nominal check rejects `this` there otherwise.
|
||||
nextAccountIdx = 0;
|
||||
private baseUrl: string;
|
||||
private proxyUrlMap = new Map<string, string>();
|
||||
private static encoder = new TextEncoder();
|
||||
|
||||
constructor() {
|
||||
super("mimocode", { format: "openai" });
|
||||
this.baseUrl = this.getBaseUrls()[0] || "https://api.xiaomimimo.com";
|
||||
this.accounts.push({
|
||||
fingerprint: generateFingerprint(),
|
||||
jwt: "",
|
||||
expiresAt: 0,
|
||||
cooldownUntil: 0,
|
||||
consecutiveFails: 0,
|
||||
// #3837/#5521 backward compat: default the per-account proxy to null (not undefined),
|
||||
// mirroring the syncAccountsFromCredentials() account builder, so an executor with no
|
||||
// accountProxies config still exposes `acct.proxy === null` on every account.
|
||||
proxy: null,
|
||||
});
|
||||
}
|
||||
|
||||
private getProxyDispatcher(fingerprint: string): Dispatcher | undefined {
|
||||
const proxyUrl = this.proxyUrlMap.get(fingerprint);
|
||||
if (!proxyUrl) return undefined;
|
||||
return createProxyDispatcher(proxyUrl);
|
||||
}
|
||||
|
||||
private fetchWithProxy(url: string, init: RequestInit, fingerprint: string): Promise<Response> {
|
||||
const dispatcher = this.getProxyDispatcher(fingerprint);
|
||||
if (dispatcher) {
|
||||
// undici fetch returns undici.Response which is structurally compatible with
|
||||
// the global Response but nominally different — same pattern as proxyFetch.ts
|
||||
const undiciFn = undiciFetch as unknown as (
|
||||
url: string,
|
||||
init: RequestInit & { dispatcher?: unknown }
|
||||
) => Promise<Response>;
|
||||
return undiciFn(url, { ...init, dispatcher });
|
||||
}
|
||||
return fetch(url, init);
|
||||
}
|
||||
|
||||
private syncAccountsFromCredentials(credentials: ProviderCredentials): void {
|
||||
const psd = credentials?.providerSpecificData;
|
||||
const fingerprints = psd?.fingerprints;
|
||||
|
||||
const accountProxies = psd?.accountProxies as AccountProxyConfig[] | undefined;
|
||||
|
||||
// #5521: build the per-fingerprint proxy URL map that getProxyDispatcher() consumes
|
||||
// to route each account's traffic through its own SOCKS5/HTTP dispatcher.
|
||||
if (Array.isArray(accountProxies)) {
|
||||
for (const entry of accountProxies) {
|
||||
if (entry?.fingerprint && entry?.proxy?.host) {
|
||||
const {
|
||||
type = "socks5",
|
||||
host,
|
||||
port,
|
||||
username,
|
||||
password,
|
||||
} = entry.proxy as {
|
||||
type?: string;
|
||||
host: string;
|
||||
port?: number;
|
||||
username?: string;
|
||||
password?: string;
|
||||
};
|
||||
const resolvedPort = port ?? (type === "socks5" ? 1080 : 8080);
|
||||
const auth = username
|
||||
? `${encodeURIComponent(username)}:${password ? encodeURIComponent(password) : ""}@`
|
||||
: "";
|
||||
this.proxyUrlMap.set(entry.fingerprint, `${type}://${auth}${host}:${resolvedPort}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #3837: register any newly-advertised fingerprints as accounts.
|
||||
if (Array.isArray(fingerprints)) {
|
||||
const existing = new Set(this.accounts.map((a) => a.fingerprint));
|
||||
for (const fp of fingerprints) {
|
||||
if (typeof fp === "string" && !existing.has(fp)) {
|
||||
this.accounts.push({
|
||||
fingerprint: fp,
|
||||
jwt: "",
|
||||
expiresAt: 0,
|
||||
cooldownUntil: 0,
|
||||
consecutiveFails: 0,
|
||||
proxy: null,
|
||||
});
|
||||
existing.add(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #3837: resolve each account's structured proxy config from accountProxies.
|
||||
const proxyMap = Array.isArray(accountProxies)
|
||||
? new Map(accountProxies.map((ap) => [ap.fingerprint, ap.proxy] as const))
|
||||
: null;
|
||||
for (const acct of this.accounts) {
|
||||
if (proxyMap) {
|
||||
const entry = proxyMap.get(acct.fingerprint);
|
||||
acct.proxy = entry !== undefined ? (entry ?? null) : null;
|
||||
} else {
|
||||
acct.proxy = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async getJwtForAccount(
|
||||
account: AccountState,
|
||||
signal?: AbortSignal | null
|
||||
): Promise<string> {
|
||||
if (isAccountReady(account)) return account.jwt;
|
||||
const dispatcher = this.getProxyDispatcher(account.fingerprint);
|
||||
const result = await bootstrapJwt(this.baseUrl, account.fingerprint, signal, dispatcher);
|
||||
account.jwt = result.jwt;
|
||||
account.expiresAt = result.expiresAt;
|
||||
return account.jwt;
|
||||
}
|
||||
|
||||
private pickAccount(): AccountState {
|
||||
return pickRotatableAccount(this.accounts, this, isAccountReady);
|
||||
}
|
||||
|
||||
private markCooldown(account: AccountState): void {
|
||||
markAccountCooldown(account);
|
||||
}
|
||||
|
||||
private markSuccess(account: AccountState): void {
|
||||
markAccountSuccess(account);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST the request with the account's JWT; on auth failure (401/403), re-bootstrap
|
||||
* the account's JWT and retry once. Mutates `headers`' Authorization in place.
|
||||
*/
|
||||
private async fetchWithAuthRetry(
|
||||
url: string,
|
||||
headers: Record<string, string>,
|
||||
reqBody: unknown,
|
||||
signal: AbortSignal | null | undefined,
|
||||
account: AccountState,
|
||||
log: ExecuteInput["log"]
|
||||
): Promise<Response> {
|
||||
const jwt = await this.getJwtForAccount(account, signal);
|
||||
headers["Authorization"] = `Bearer ${jwt}`;
|
||||
|
||||
const resp = await this.fetchWithProxy(
|
||||
url,
|
||||
{
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify(reqBody),
|
||||
signal: signal ?? undefined,
|
||||
},
|
||||
account.fingerprint
|
||||
);
|
||||
if (resp.status !== 401 && resp.status !== 403) return resp;
|
||||
|
||||
// On auth failure, re-bootstrap this account and retry once
|
||||
log?.warn?.(
|
||||
"MIMOCODE",
|
||||
`Auth failed (${resp.status}) on account ${account.fingerprint.slice(0, 8)}…`
|
||||
);
|
||||
account.jwt = "";
|
||||
account.expiresAt = 0;
|
||||
account.consecutiveFails = 0;
|
||||
const freshJwt = await this.getJwtForAccount(account, signal);
|
||||
headers["Authorization"] = `Bearer ${freshJwt}`;
|
||||
return this.fetchWithProxy(
|
||||
url,
|
||||
{
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify(reqBody),
|
||||
signal: signal ?? undefined,
|
||||
},
|
||||
account.fingerprint
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gate 429/400 statuses before the success path: a 429 — or a 400 carrying
|
||||
* MiMoCode's rate-limit text — puts the account on cooldown and rotates; any other
|
||||
* 400 fails fast with the sanitized upstream error (#2101/#4976, see
|
||||
* handleBadRequest). Returns "rotate", a fail-fast Response, or null to proceed.
|
||||
*/
|
||||
private async gateRetryableStatus(
|
||||
resp: Response,
|
||||
account: AccountState,
|
||||
log: ExecuteInput["log"]
|
||||
): Promise<"rotate" | Response | null> {
|
||||
if (resp.status === 429) {
|
||||
this.markCooldown(account);
|
||||
log?.warn?.(
|
||||
"MIMOCODE",
|
||||
`Rate limited on account ${account.fingerprint.slice(0, 8)}, trying next…`
|
||||
);
|
||||
return "rotate";
|
||||
}
|
||||
if (resp.status !== 400) return null;
|
||||
return (await this.handleBadRequest(resp, account, log)) ?? "rotate";
|
||||
}
|
||||
|
||||
/**
|
||||
* Classify a 400 response body (#2101/#4976).
|
||||
*
|
||||
* #4976: MiMoCode signals throttling via a non-standard 400 whose body carries
|
||||
* rate-limit semantics (e.g. "Detected high-frequency non-compliant requests from
|
||||
* you.") instead of a 429 — same RATE_LIMIT_TEXT_PATTERNS as accountFallback.ts's
|
||||
* checkFallbackError(), so the two call sites never disagree on what counts as
|
||||
* throttling. That case puts the account on cooldown and returns `null` (rotate).
|
||||
*
|
||||
* #2101: any other 400 is a genuinely malformed request that fails identically on
|
||||
* every account — rotating would waste N round-trips, cooldown every account (a
|
||||
* provider-wide outage for parallel requests), and hide the real diagnostic behind
|
||||
* a generic exhaustion error. That case returns a fail-fast 400 Response carrying
|
||||
* the sanitized upstream message, without touching cooldown/success state.
|
||||
*/
|
||||
private async handleBadRequest(
|
||||
resp: Response,
|
||||
account: AccountState,
|
||||
log: ExecuteInput["log"]
|
||||
): Promise<Response | null> {
|
||||
const bodyText = await resp.text().catch(() => "");
|
||||
|
||||
if (RATE_LIMIT_TEXT_PATTERNS.some((p) => p.test(bodyText))) {
|
||||
this.markCooldown(account);
|
||||
log?.warn?.(
|
||||
"MIMOCODE",
|
||||
`Rate-limit-style 400 on account ${account.fingerprint.slice(0, 8)}, trying next…`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
log?.warn?.(
|
||||
"MIMOCODE",
|
||||
`Malformed request (400) on account ${account.fingerprint.slice(0, 8)}, not retrying`
|
||||
);
|
||||
let upstreamMessage = bodyText;
|
||||
try {
|
||||
const parsed = JSON.parse(bodyText) as { error?: { message?: string } };
|
||||
if (parsed?.error?.message) upstreamMessage = parsed.error.message;
|
||||
} catch {
|
||||
/* body wasn't JSON — use raw text */
|
||||
}
|
||||
const errorBody = buildErrorBody(400, sanitizeErrorMessage(upstreamMessage || "Bad request"));
|
||||
return new Response(MimocodeExecutor.encoder.encode(JSON.stringify(errorBody)), {
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
|
||||
buildUrl(
|
||||
_model: string,
|
||||
_stream: boolean,
|
||||
_urlIndex = 0,
|
||||
_credentials?: ProviderCredentials | null
|
||||
): string {
|
||||
return `${this.baseUrl.replace(/\/$/, "")}${CHAT_PATH}`;
|
||||
}
|
||||
|
||||
buildHeaders(
|
||||
_credentials: ProviderCredentials,
|
||||
stream = true,
|
||||
_clientHeaders?: Record<string, string> | null,
|
||||
_model?: string
|
||||
): Record<string, string> {
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Mimo-Source": MIMO_SOURCE,
|
||||
"User-Agent": USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)],
|
||||
};
|
||||
if (stream) headers["Accept"] = "text/event-stream, application/json";
|
||||
return headers;
|
||||
}
|
||||
|
||||
transformRequest(
|
||||
model: string,
|
||||
body: unknown,
|
||||
_stream: boolean,
|
||||
_credentials?: ProviderCredentials | null
|
||||
): unknown {
|
||||
if (typeof body === "object" && body !== null) {
|
||||
const withModel = { ...(body as Record<string, unknown>), model: rewriteModelName(model) };
|
||||
return injectSystemMarker(withModel);
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
async testConnection(
|
||||
_credentials: ProviderCredentials,
|
||||
_signal?: AbortSignal | null,
|
||||
log?: ExecuteInput["log"]
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
this.syncAccountsFromCredentials(_credentials);
|
||||
const account = this.accounts[0];
|
||||
const jwt = await this.getJwtForAccount(account, _signal);
|
||||
const resp = await this.fetchWithProxy(
|
||||
this.buildUrl("mimo-auto", false),
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${jwt}`,
|
||||
"X-Mimo-Source": MIMO_SOURCE,
|
||||
},
|
||||
body: JSON.stringify(
|
||||
injectSystemMarker({
|
||||
model: "mimo-auto",
|
||||
messages: [{ role: "user", content: "ping" }],
|
||||
stream: false,
|
||||
})
|
||||
),
|
||||
signal: _signal ?? undefined,
|
||||
},
|
||||
account.fingerprint
|
||||
);
|
||||
return resp.status === 200;
|
||||
} catch {
|
||||
log?.warn?.("MIMOCODE", "testConnection network error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async execute(input: ExecuteInput): Promise<{
|
||||
response: Response;
|
||||
url: string;
|
||||
headers: Record<string, string>;
|
||||
transformedBody: unknown;
|
||||
}> {
|
||||
const { model, stream, body, signal, log } = input;
|
||||
const encoder = MimocodeExecutor.encoder;
|
||||
|
||||
if (signal?.aborted) {
|
||||
return {
|
||||
response: new Response(
|
||||
encoder.encode(
|
||||
JSON.stringify({
|
||||
error: { message: "Request aborted", type: "abort", code: "ABORTED" },
|
||||
})
|
||||
),
|
||||
{ status: 499, headers: { "Content-Type": "application/json" } }
|
||||
),
|
||||
url: this.buildUrl(model, stream),
|
||||
headers: this.buildHeaders(input.credentials, stream),
|
||||
transformedBody: body,
|
||||
};
|
||||
}
|
||||
|
||||
const url = this.buildUrl(model, stream);
|
||||
const reqBody = this.transformRequest(model, body, stream, input.credentials);
|
||||
|
||||
this.syncAccountsFromCredentials(input.credentials);
|
||||
|
||||
const sharedEgressGuardEnabled = isNetworkRotationSharedEgressGuardEnabled();
|
||||
// Set once a proxy-less account's network throw reveals the shared egress
|
||||
// is down — subsequent proxy-less accounts this request are skipped
|
||||
// without a network call, but proxied accounts (independent egress) are
|
||||
// still tried normally. See NETWORK_ROTATION_SHARED_EGRESS_GUARD.
|
||||
let sharedEgressDown = false;
|
||||
|
||||
// Try each account, skip cooldown ones
|
||||
for (let attempt = 0; attempt < this.accounts.length; attempt++) {
|
||||
const account = this.pickAccount();
|
||||
|
||||
if (sharedEgressGuardEnabled && sharedEgressDown && !account.proxy) {
|
||||
log?.warn?.(
|
||||
"MIMOCODE",
|
||||
`skipping account ${maskAccountId(account.fingerprint)} (no dedicated proxy, shared egress already down this request)`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const headers = this.buildHeaders(input.credentials, stream);
|
||||
const resp = await this.fetchWithAuthRetry(url, headers, reqBody, signal, account, log);
|
||||
|
||||
// 429/400 gating (#2101/#4976): cooldown+rotate, fail fast, or proceed.
|
||||
const gate = await this.gateRetryableStatus(resp, account, log);
|
||||
if (gate === "rotate") continue;
|
||||
if (gate) {
|
||||
return {
|
||||
response: gate,
|
||||
url,
|
||||
headers: this.buildHeaders(input.credentials, stream),
|
||||
transformedBody: reqBody,
|
||||
};
|
||||
}
|
||||
|
||||
this.markSuccess(account);
|
||||
const respHeaders: Record<string, string> = {};
|
||||
resp.headers.forEach((v, k) => {
|
||||
respHeaders[k] = v;
|
||||
});
|
||||
return {
|
||||
response: resp as unknown as Response,
|
||||
url,
|
||||
headers: respHeaders,
|
||||
transformedBody: reqBody,
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const masked = maskAccountId(account.fingerprint);
|
||||
|
||||
// Mirrors OpencodeExecutor's rotation guard: a network exception is only account-scoped
|
||||
// when this account has its OWN egress (a configured proxy). Without
|
||||
// one, accounts share the default egress — the failure isn't
|
||||
// attributable to this account, and trying the next one would just
|
||||
// retry the same outage while poisoning its cooldown for a cause
|
||||
// that isn't theirs. Fail fast instead of exhausting every account.
|
||||
if (!isNetworkErrorRotatable(account)) {
|
||||
if (sharedEgressGuardEnabled) {
|
||||
this.markCooldown(account);
|
||||
sharedEgressDown = true;
|
||||
log?.warn?.(
|
||||
"MIMOCODE",
|
||||
`network error on account ${masked} (no dedicated proxy, shared egress), cooldown applied — trying next available account… (${msg})`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
log?.warn?.(
|
||||
"MIMOCODE",
|
||||
`network error on account ${masked} (no dedicated proxy, shared egress) — not rotating (${msg})`
|
||||
);
|
||||
return {
|
||||
response: new Response(
|
||||
encoder.encode(
|
||||
JSON.stringify(
|
||||
buildErrorBody(502, msg, undefined, {
|
||||
type: "upstream_error",
|
||||
code: "EXECUTOR_ERROR",
|
||||
})
|
||||
)
|
||||
),
|
||||
{ status: 502, headers: { "Content-Type": "application/json" } }
|
||||
),
|
||||
url,
|
||||
headers: this.buildHeaders(input.credentials, stream),
|
||||
transformedBody: body,
|
||||
};
|
||||
}
|
||||
|
||||
this.markCooldown(account);
|
||||
log?.warn?.("MIMOCODE", `network error on account ${masked}, rotating to next… (${msg})`);
|
||||
if (attempt === this.accounts.length - 1) {
|
||||
log?.error?.("MIMOCODE", `Executor error: ${msg}`);
|
||||
return {
|
||||
response: new Response(
|
||||
encoder.encode(
|
||||
JSON.stringify(
|
||||
buildErrorBody(502, msg, undefined, {
|
||||
type: "upstream_error",
|
||||
code: "EXECUTOR_ERROR",
|
||||
})
|
||||
)
|
||||
),
|
||||
{ status: 502, headers: { "Content-Type": "application/json" } }
|
||||
),
|
||||
url,
|
||||
headers: this.buildHeaders(input.credentials, stream),
|
||||
transformedBody: body,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
response: new Response(
|
||||
encoder.encode(
|
||||
JSON.stringify({
|
||||
error: {
|
||||
message: "All accounts exhausted",
|
||||
type: "upstream_error",
|
||||
code: "NO_ACCOUNTS",
|
||||
},
|
||||
})
|
||||
),
|
||||
{ status: 502, headers: { "Content-Type": "application/json" } }
|
||||
),
|
||||
url,
|
||||
headers: this.buildHeaders(input.credentials, stream),
|
||||
transformedBody: body,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default MimocodeExecutor;
|
||||
@@ -239,13 +239,10 @@ describe("TierResolver", () => {
|
||||
|
||||
it("deriveNoAuthFreeProviders includes all chat-tier noAuth providers", () => {
|
||||
const derived = deriveNoAuthFreeProviders();
|
||||
// opencode + mimocode are the ones the bug report called out
|
||||
// opencode is one of the no-auth providers the bug report called out
|
||||
expect(derived.includes("opencode"), "opencode should be in derived noAuth-free list").toBe(
|
||||
true
|
||||
);
|
||||
expect(derived.includes("mimocode"), "mimocode should be in derived noAuth-free list").toBe(
|
||||
true
|
||||
);
|
||||
expect(derived.includes("duckduckgo-web")).toBe(true);
|
||||
});
|
||||
|
||||
@@ -271,12 +268,6 @@ describe("TierResolver", () => {
|
||||
expect(result.hasFreeTier).toBe(true);
|
||||
});
|
||||
|
||||
it("classifyTier classifies mimocode/mimo-auto as free via noAuth derivation", () => {
|
||||
const result = classifyTier("mimocode", "mimo-auto");
|
||||
expect(result.tier).toBe(PROVIDER_TIER.FREE);
|
||||
expect(result.hasFreeTier).toBe(true);
|
||||
});
|
||||
|
||||
it("classifyTier still returns cheap for paid glm-5.1 (no regression)", () => {
|
||||
// glm-5.1 is not in freeProviders, costs $0.50/M → cheap tier.
|
||||
// Make sure the new noAuth derivation didn't accidentally pull it into free.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import type { ResolvedComboTarget } from "./types.ts";
|
||||
|
||||
/** Providers whose `providerSpecificData.fingerprints` array should be expanded. */
|
||||
const FINGERPRINT_PROVIDERS: ReadonlySet<string> = new Set(["mimocode", "mcode", "opencode"]);
|
||||
const FINGERPRINT_PROVIDERS: ReadonlySet<string> = new Set(["opencode"]);
|
||||
|
||||
/** Separator the combo builder UI uses to encode an account pin (#6087). */
|
||||
const FP_PIN_SEPARATOR = "|fp|";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "omniroute",
|
||||
"version": "3.8.50",
|
||||
"description": "Unified AI router with 341 providers, RTK+Caveman compression, auto fallback, MCP/A2A, desktop, PWA, and OpenAI-compatible APIs.",
|
||||
"description": "Unified AI router with 340 providers, RTK+Caveman compression, auto fallback, MCP/A2A, desktop, PWA, and OpenAI-compatible APIs.",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"omniroute": "bin/omniroute.mjs",
|
||||
|
||||
@@ -8,7 +8,6 @@ import { useNotificationStore } from "@/store/notificationStore";
|
||||
import { providerText } from "../providerPageHelpers";
|
||||
|
||||
const ACCOUNT_PROVIDER_NAMES: Record<string, string> = {
|
||||
mimocode: "MiMoCode",
|
||||
opencode: "OpenCode",
|
||||
dahl: "Dahl",
|
||||
};
|
||||
|
||||
@@ -402,7 +402,6 @@ const LOBE_PROVIDER_ALIASES = {
|
||||
"meta-llama": "Meta",
|
||||
minimax: "Minimax",
|
||||
"minimax-cn": "Minimax",
|
||||
mimocode: "XiaomiMiMo",
|
||||
mistral: "Mistral",
|
||||
mistralai: "Mistral",
|
||||
moonshot: "Moonshot",
|
||||
|
||||
@@ -30,7 +30,6 @@ export const FREE_PROVIDERS = {};
|
||||
|
||||
export const FREE_APIKEY_PROVIDER_IDS = new Set([
|
||||
"qoder",
|
||||
"mimocode",
|
||||
"opencode",
|
||||
"dahl",
|
||||
// auggie is a fully local, credential-less CLI passthrough (auth handled by
|
||||
|
||||
@@ -118,25 +118,6 @@ export const NOAUTH_PROVIDERS = {
|
||||
freeNote: "Free video generation — VEO 3.1, Seedance. 6 requests/hour.",
|
||||
authHint: "No auth required. Rate limited to 6 requests/hour per IP.",
|
||||
},
|
||||
mimocode: {
|
||||
id: "mimocode",
|
||||
alias: "mcode",
|
||||
name: "MiMoCode (Free)",
|
||||
icon: "devices",
|
||||
color: "#FF6B35",
|
||||
textIcon: "MC",
|
||||
website: "https://mimo.mi.com",
|
||||
noAuth: true,
|
||||
hasFree: true,
|
||||
serviceKinds: ["llm"],
|
||||
freeNote:
|
||||
"Free — Xiaomi MiMo models via bootstrap JWT auth. No API key required. Supports streaming.",
|
||||
authHint:
|
||||
"No API key required. The executor auto-generates JWT tokens via device fingerprint bootstrap.",
|
||||
notice: {
|
||||
text: "MiMoCode uses Xiaomi's public free AI endpoint with bootstrap-based JWT authentication. No signup needed. Rate limits apply.",
|
||||
},
|
||||
},
|
||||
auggie: {
|
||||
id: "auggie",
|
||||
alias: "aug",
|
||||
|
||||
@@ -51,7 +51,6 @@ const NO_AUTH_PROVIDER_IDS = [
|
||||
"theoldllm",
|
||||
"chipotle",
|
||||
"veoaifree-web",
|
||||
"mimocode",
|
||||
"auggie",
|
||||
];
|
||||
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
import { describe, it, before } from "node:test";
|
||||
import assert from "node:assert";
|
||||
import { MimocodeExecutor, generateFingerprint } from "../../open-sse/executors/mimocode.ts";
|
||||
|
||||
const PROXY_URL = process.env.MIMOCODE_SOCKS5_PROXY;
|
||||
|
||||
function parseProxyUrl(url: string): { type: string; host: string; port: number } | null {
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
return { type: parsed.protocol.replace(":", ""), host: parsed.hostname, port: parsed.port ? Number(parsed.port) : 1080 };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function requireProxy() {
|
||||
if (!PROXY_URL) {
|
||||
return false;
|
||||
}
|
||||
const parsed = parseProxyUrl(PROXY_URL);
|
||||
return parsed !== null;
|
||||
}
|
||||
|
||||
const proxyConfig = PROXY_URL ? parseProxyUrl(PROXY_URL) : null;
|
||||
|
||||
describe("mimocode per-account proxy — SOCKS5 integration", { timeout: 30_000 }, () => {
|
||||
before(() => {
|
||||
if (!PROXY_URL) {
|
||||
console.log("# MIMOCODE_SOCKS5_PROXY not set, skipping live proxy tests");
|
||||
}
|
||||
});
|
||||
|
||||
it("bootstrap returns JWT through configured proxy", { skip: !requireProxy() ? "MIMOCODE_SOCKS5_PROXY not set" : false }, async () => {
|
||||
process.env.ENABLE_SOCKS5_PROXY = "true";
|
||||
const { Socks5ProxyAgent } = await import("undici");
|
||||
const agent = new Socks5ProxyAgent(PROXY_URL!);
|
||||
|
||||
const fp = generateFingerprint("integration-bootstrap-" + Date.now());
|
||||
const resp = await fetch("https://api.xiaomimimo.com/api/free-ai/bootstrap", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ client: fp }),
|
||||
// @ts-expect-error — undici dispatcher
|
||||
dispatcher: agent,
|
||||
signal: AbortSignal.timeout(15_000),
|
||||
});
|
||||
assert.strictEqual(resp.status, 200, `Bootstrap through proxy: expected 200, got ${resp.status}`);
|
||||
const data = await resp.json();
|
||||
assert.ok(data.jwt, "Response should contain JWT");
|
||||
assert.ok(typeof data.jwt === "string" && data.jwt.length > 10, "JWT should be a non-trivial string");
|
||||
});
|
||||
|
||||
it("chat request succeeds through configured proxy", { skip: !requireProxy() ? "MIMOCODE_SOCKS5_PROXY not set" : false }, async () => {
|
||||
process.env.ENABLE_SOCKS5_PROXY = "true";
|
||||
const { Socks5ProxyAgent } = await import("undici");
|
||||
const agent = new Socks5ProxyAgent(PROXY_URL!);
|
||||
|
||||
const fp = generateFingerprint("integration-chat-" + Date.now());
|
||||
const bootstrapResp = await fetch("https://api.xiaomimimo.com/api/free-ai/bootstrap", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ client: fp }),
|
||||
// @ts-expect-error — undici dispatcher
|
||||
dispatcher: agent,
|
||||
signal: AbortSignal.timeout(15_000),
|
||||
});
|
||||
assert.strictEqual(bootstrapResp.status, 200);
|
||||
const { jwt } = await bootstrapResp.json();
|
||||
|
||||
const chatResp = await fetch("https://api.xiaomimimo.com/api/free-ai/openai/chat", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${jwt}`,
|
||||
"X-Mimo-Source": "mimocode-cli-free",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: "mimo-auto",
|
||||
messages: [
|
||||
{ role: "system", content: "You are MiMoCode, an interactive CLI tool that helps users with software engineering tasks." },
|
||||
{ role: "user", content: "Say exactly: proxy-integration-ok" },
|
||||
],
|
||||
stream: false,
|
||||
}),
|
||||
// @ts-expect-error — undici dispatcher
|
||||
dispatcher: agent,
|
||||
signal: AbortSignal.timeout(20_000),
|
||||
});
|
||||
assert.ok(chatResp.status === 200 || chatResp.status === 429,
|
||||
`Chat through proxy: expected 200/429, got ${chatResp.status}`);
|
||||
});
|
||||
|
||||
it("accounts carry proxy config after sync", () => {
|
||||
const exec = new MimocodeExecutor();
|
||||
const fp = "integration-fp-1";
|
||||
const cfg = proxyConfig || { type: "socks5", host: "127.0.0.1", port: 1080 };
|
||||
(exec as any).accounts = [
|
||||
{ fingerprint: fp, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0, proxy: null },
|
||||
];
|
||||
(exec as any).nextAccountIdx = 0;
|
||||
|
||||
(exec as any).syncAccountsFromCredentials({
|
||||
providerSpecificData: {
|
||||
accountProxies: [{ fingerprint: fp, proxy: cfg }],
|
||||
},
|
||||
});
|
||||
|
||||
const acct = (exec as any).accounts.find((a: any) => a.fingerprint === fp);
|
||||
assert.ok(acct, "Account should exist");
|
||||
assert.deepStrictEqual(acct.proxy, cfg);
|
||||
});
|
||||
|
||||
it("two accounts with different proxies tracked independently", () => {
|
||||
const exec = new MimocodeExecutor();
|
||||
const fp1 = "integration-fp-a";
|
||||
const fp2 = "integration-fp-b";
|
||||
const proxy1 = { type: "http" as const, host: "proxy-a.example.com", port: 8080 };
|
||||
const proxy2 = { type: "socks5" as const, host: "proxy-b.example.com", port: 1080 };
|
||||
|
||||
(exec as any).accounts = [
|
||||
{ fingerprint: fp1, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0, proxy: null },
|
||||
{ fingerprint: fp2, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0, proxy: null },
|
||||
];
|
||||
(exec as any).nextAccountIdx = 0;
|
||||
|
||||
(exec as any).syncAccountsFromCredentials({
|
||||
providerSpecificData: {
|
||||
accountProxies: [
|
||||
{ fingerprint: fp1, proxy: proxy1 },
|
||||
{ fingerprint: fp2, proxy: proxy2 },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const a1 = (exec as any).accounts.find((a: any) => a.fingerprint === fp1);
|
||||
const a2 = (exec as any).accounts.find((a: any) => a.fingerprint === fp2);
|
||||
assert.deepStrictEqual(a1.proxy, proxy1, "Account 1 should have proxy1");
|
||||
assert.deepStrictEqual(a2.proxy, proxy2, "Account 2 should have proxy2");
|
||||
assert.notDeepStrictEqual(a1.proxy, a2.proxy, "Proxies should differ");
|
||||
});
|
||||
|
||||
it("no accountProxies keeps all proxies null (backward compat)", () => {
|
||||
const exec = new MimocodeExecutor();
|
||||
const accounts = (exec as any).accounts;
|
||||
assert.ok(accounts.length >= 1);
|
||||
for (const acct of accounts) {
|
||||
assert.strictEqual(acct.proxy, null, "Default account proxy should be null");
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -3625,29 +3625,6 @@
|
||||
"stream": "https://api.llama.com/compat/v1/chat/completions"
|
||||
}
|
||||
},
|
||||
"mimocode": {
|
||||
"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.xiaomimimo.com",
|
||||
"stream": "https://api.xiaomimimo.com"
|
||||
}
|
||||
},
|
||||
"minimax": {
|
||||
"format": "openai",
|
||||
"headers": {
|
||||
|
||||
@@ -18,14 +18,14 @@ test("#4976 400 with rate-limit text (MiMoCode) → fallback with RATE_LIMIT_EXC
|
||||
"Detected high-frequency non-compliant requests from you.",
|
||||
0,
|
||||
null,
|
||||
"mimocode"
|
||||
"theoldllm"
|
||||
);
|
||||
assert.equal(res.shouldFallback, true);
|
||||
assert.equal(res.reason, RateLimitReason.RATE_LIMIT_EXCEEDED);
|
||||
});
|
||||
|
||||
test("#4976 400 with Chinese rate-limit text → fallback with RATE_LIMIT_EXCEEDED", () => {
|
||||
const res = checkFallbackError(400, "检测到您的请求频率过高,请稍后再试", 0, null, "mimocode");
|
||||
const res = checkFallbackError(400, "检测到您的请求频率过高,请稍后再试", 0, null, "theoldllm");
|
||||
assert.equal(res.shouldFallback, true);
|
||||
assert.equal(res.reason, RateLimitReason.RATE_LIMIT_EXCEEDED);
|
||||
});
|
||||
|
||||
@@ -49,13 +49,6 @@ test("#3061 opencode-zen no-auth: first selection returns synthetic noauth (happ
|
||||
assert.equal((creds as { connectionId?: string }).connectionId, "noauth");
|
||||
});
|
||||
|
||||
test("#3061 mimocode no-auth: first selection returns synthetic noauth (happy path preserved)", async () => {
|
||||
const creds = await getProviderCredentials("mimocode", null, null, "mimo-auto");
|
||||
assert.ok(creds, "mimocode must resolve to synthetic no-auth credentials on first selection");
|
||||
assert.equal((creds as { connectionId?: string }).connectionId, "noauth");
|
||||
assert.equal((creds as { apiKey?: unknown }).apiKey, null);
|
||||
});
|
||||
|
||||
// ── The fix: once "noauth" is excluded, selection MUST stop (return null) ──
|
||||
|
||||
test("#3061 opencode no-auth: excluding 'noauth' returns null (breaks the fallback loop)", async () => {
|
||||
@@ -81,13 +74,3 @@ test("#3061 opencode-zen no-auth: excluding 'noauth' returns null (breaks the fa
|
||||
);
|
||||
});
|
||||
|
||||
test("#3061 mimocode no-auth: excluding 'noauth' returns null (breaks the fallback loop)", async () => {
|
||||
const creds = await getProviderCredentials("mimocode", null, null, "mimo-auto", {
|
||||
excludeConnectionIds: ["noauth"],
|
||||
});
|
||||
assert.equal(
|
||||
creds,
|
||||
null,
|
||||
"excluded synthetic noauth must not be re-selected for the mimocode keyless path"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -47,15 +47,14 @@ describe("suffixComposition :free tier (#4517)", () => {
|
||||
});
|
||||
|
||||
it("buildAutoCandidateFilter keeps noAuth free providers", () => {
|
||||
// Regression: opencode and mimocode are noAuth and free, but the
|
||||
// pre-fix `freeProviders` list omitted them, so the filter rejected
|
||||
// their candidates even though they ARE free upstream.
|
||||
// Regression: opencode was noAuth and free, but the
|
||||
// pre-fix `freeProviders` list omitted it, so the filter rejected
|
||||
// its candidates even though it IS free upstream.
|
||||
const filter = buildAutoCandidateFilter("coding", "free");
|
||||
assert.notEqual(filter, null);
|
||||
|
||||
assert.equal(filter!({ provider: "opencode", model: "big-pickle" }), true);
|
||||
assert.equal(filter!({ provider: "opencode", model: "minimax-m3-free" }), true);
|
||||
assert.equal(filter!({ provider: "mimocode", model: "mimo-auto" }), true);
|
||||
assert.equal(filter!({ provider: "duckduckgo-web", model: "gpt-4o-mini" }), true);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
// #5521 — A mimocode connection with multiple fingerprints in
|
||||
// #5521 — An opencode connection with multiple fingerprints in
|
||||
// provider_specific_data.fingerprints was treated as a single combo target,
|
||||
// so only one fingerprint (one IP) was used per request. The combo system
|
||||
// must now expand each fingerprint into its own target so all of them
|
||||
@@ -17,13 +17,6 @@ const {
|
||||
|
||||
// ── isFingerprintProvider ────────────────────────────────────────────────────
|
||||
|
||||
test("isFingerprintProvider: mimocode returns true", () => {
|
||||
assert.equal(isFingerprintProvider("mimocode"), true);
|
||||
});
|
||||
|
||||
test("isFingerprintProvider: mcode returns true", () => {
|
||||
assert.equal(isFingerprintProvider("mcode"), true);
|
||||
});
|
||||
|
||||
test("isFingerprintProvider: opencode returns true", () => {
|
||||
assert.equal(isFingerprintProvider("opencode"), true);
|
||||
@@ -136,8 +129,8 @@ function makeTarget(overrides: Record<string, unknown> = {}) {
|
||||
kind: "model" as const,
|
||||
stepId: "step-0",
|
||||
executionKey: "step-0",
|
||||
modelStr: "mimocode/mimo-auto",
|
||||
provider: "mimocode",
|
||||
modelStr: "opencode/kimi-k2",
|
||||
provider: "opencode",
|
||||
providerId: null,
|
||||
connectionId: "conn-1",
|
||||
weight: 0,
|
||||
@@ -149,7 +142,7 @@ function makeTarget(overrides: Record<string, unknown> = {}) {
|
||||
function makeConnection(fps: string[]) {
|
||||
return {
|
||||
id: "conn-1",
|
||||
provider: "mimocode",
|
||||
provider: "opencode",
|
||||
providerSpecificData: { fingerprints: fps },
|
||||
};
|
||||
}
|
||||
@@ -196,7 +189,7 @@ test("expandTargetsByFingerprints: preserves all target properties across copies
|
||||
const fps = ["fp-aaa", "fp-bbb", "fp-ccc"];
|
||||
const conn = makeConnection(fps);
|
||||
const targets = [
|
||||
makeTarget({ connectionId: "conn-1", modelStr: "mimocode/mimo-auto", weight: 5 }),
|
||||
makeTarget({ connectionId: "conn-1", modelStr: "opencode/kimi-k2", weight: 5 }),
|
||||
];
|
||||
const connById = new Map([["conn-1", conn]]);
|
||||
const result = expandTargetsByFingerprints(targets, connById, (t) => t.provider);
|
||||
@@ -204,8 +197,8 @@ test("expandTargetsByFingerprints: preserves all target properties across copies
|
||||
for (const r of result) {
|
||||
assert.equal(r.kind, "model");
|
||||
assert.equal(r.connectionId, "conn-1");
|
||||
assert.equal(r.modelStr, "mimocode/mimo-auto");
|
||||
assert.equal(r.provider, "mimocode");
|
||||
assert.equal(r.modelStr, "opencode/kimi-k2");
|
||||
assert.equal(r.provider, "opencode");
|
||||
assert.equal(r.weight, 5);
|
||||
}
|
||||
});
|
||||
@@ -242,23 +235,6 @@ test("expandTargetsByFingerprints: empty input returns empty array", () => {
|
||||
assert.equal(result.length, 0);
|
||||
});
|
||||
|
||||
test("expandTargetsByFingerprints: mcode provider expands correctly", () => {
|
||||
const fps = ["mfp-1", "mfp-2", "mfp-3"];
|
||||
const conn = {
|
||||
id: "conn-m",
|
||||
provider: "mcode",
|
||||
providerSpecificData: { fingerprints: fps },
|
||||
};
|
||||
const targets = [
|
||||
makeTarget({ provider: "mcode", modelStr: "mcode/auto", connectionId: "conn-m" }),
|
||||
];
|
||||
const connById = new Map([["conn-m", conn]]);
|
||||
const result = expandTargetsByFingerprints(targets, connById, (t) => t.provider);
|
||||
assert.equal(result.length, 3);
|
||||
assert.equal(result[0].executionKey, "step-0");
|
||||
assert.equal(result[1].executionKey, "step-0@fp:mfp-2");
|
||||
assert.equal(result[2].executionKey, "step-0@fp:mfp-3");
|
||||
});
|
||||
|
||||
test("expandTargetsByFingerprints: multiple targets each expand independently", () => {
|
||||
const conn1 = makeConnection(["fp-a1", "fp-a2"]);
|
||||
|
||||
@@ -2,7 +2,7 @@ import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
// #6696 — the combo builder's "pin a specific account" feature for fingerprint
|
||||
// providers (mimocode/mcode/opencode) builds a composite connectionId of the
|
||||
// providers (opencode) builds a composite connectionId of the
|
||||
// form `${rowId}|fp|${fingerprint}` (src/lib/combos/builderOptions.ts:251), but
|
||||
// nothing in the combo execution path ever splits that composite id back into
|
||||
// a real rowId + a selected fingerprint. This test proves the pin is inert:
|
||||
@@ -27,8 +27,8 @@ function makeTarget(overrides: Record<string, unknown> = {}) {
|
||||
kind: "model" as const,
|
||||
stepId: "step-0",
|
||||
executionKey: "step-0",
|
||||
modelStr: "mimocode/mimo-auto",
|
||||
provider: "mimocode",
|
||||
modelStr: "opencode/kimi-k2",
|
||||
provider: "opencode",
|
||||
providerId: null,
|
||||
connectionId: "conn-1",
|
||||
weight: 0,
|
||||
@@ -41,7 +41,7 @@ test("#6696: fp-pinned composite connectionId is never resolved to the real conn
|
||||
const realConnectionId = "conn-1";
|
||||
const conn = {
|
||||
id: realConnectionId,
|
||||
provider: "mimocode",
|
||||
provider: "opencode",
|
||||
providerSpecificData: { fingerprints: ["fp-aaa", "fp-bbb"] },
|
||||
};
|
||||
const connById = new Map([[realConnectionId, conn]]);
|
||||
@@ -81,7 +81,7 @@ test("#6696: composite connectionId never matches connectionById (root cause of
|
||||
const realConnectionId = "conn-1";
|
||||
const conn = {
|
||||
id: realConnectionId,
|
||||
provider: "mimocode",
|
||||
provider: "opencode",
|
||||
providerSpecificData: { fingerprints: ["fp-aaa", "fp-bbb"] },
|
||||
};
|
||||
const connById = new Map([[realConnectionId, conn]]);
|
||||
|
||||
@@ -157,12 +157,11 @@ test("resolveTargetFingerprint: pinned fingerprint wins", () => {
|
||||
});
|
||||
|
||||
test("resolveTargetFingerprint: parses @fp: suffix from executionKey", () => {
|
||||
assert.equal(resolveTargetFingerprint({ provider: "mcode", executionKey: "k@fp:abc" }), "abc");
|
||||
assert.equal(resolveTargetFingerprint({ provider: "opencode", executionKey: "k@fp:abc" }), "abc");
|
||||
});
|
||||
|
||||
test("resolveTargetFingerprint: null when no source", () => {
|
||||
assert.equal(resolveTargetFingerprint({ provider: "opencode", executionKey: "k" }), null);
|
||||
assert.equal(resolveTargetFingerprint({ provider: "mimocode" }), null);
|
||||
});
|
||||
|
||||
// ── Integration: hook + gate through handleComboChat (#5501) ──────────────────
|
||||
|
||||
@@ -6,16 +6,12 @@ import {
|
||||
} from "../../open-sse/services/errorClassifier.ts";
|
||||
|
||||
// #6315 / #6345 — a single generic upstream 403 on a no-credential ("authType:
|
||||
// none") provider like mimocode or theoldllm was permanently banning the whole
|
||||
// none") provider was permanently banning the whole
|
||||
// connection (classified as FORBIDDEN, a terminal type). These providers are
|
||||
// free/stateless — there is no real account/credential to revoke, so a bare
|
||||
// 403 should be RECOVERABLE (null) and handled by the existing connection
|
||||
// cooldown/retry layer, same as apikey providers already are.
|
||||
|
||||
test("#6315: mimocode 'high-frequency non-compliant' 403 -> recoverable (null), not FORBIDDEN", () => {
|
||||
const body = { error: "Detected high-frequency non-compliant requests, please slow down." };
|
||||
assert.equal(classifyProviderError(403, body, "mimocode"), null);
|
||||
});
|
||||
|
||||
test("#6345: theoldllm 'Request blocked'/access_denied 403 -> recoverable (null), not FORBIDDEN", () => {
|
||||
const body = { error: "Request blocked", type: "access_denied" };
|
||||
@@ -53,7 +49,3 @@ test("#8813: chatgpt-web SENTINEL_BLOCKED 403 with raw 'Sentinel blocked' text
|
||||
);
|
||||
});
|
||||
|
||||
test("control: recognized ban phrase on a no-credential provider still terminal (ACCOUNT_DEACTIVATED)", () => {
|
||||
const body = "This service has been disabled in this account for violation of policy.";
|
||||
assert.equal(classifyProviderError(403, body, "mimocode"), PROVIDER_ERROR_TYPES.ACCOUNT_DEACTIVATED);
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ test("free onboarding candidates come from the no-auth registry and exclude loca
|
||||
assert.ok(ids.includes("felo-web"));
|
||||
assert.ok(ids.includes("theoldllm"));
|
||||
assert.ok(ids.includes("chipotle"));
|
||||
assert.ok(ids.includes("mimocode"));
|
||||
assert.ok(ids.includes("theoldllm"));
|
||||
assert.ok(ids.includes("aihorde"));
|
||||
assert.ok(!ids.includes("devin-cli-agentic"));
|
||||
assert.ok(!ids.includes("auggie"));
|
||||
|
||||
@@ -10,7 +10,7 @@ test("batch setup creates missing providers, skips existing ones, and is retry-s
|
||||
const existing = [{ provider: "opencode", name: "My customized OpenCode" }];
|
||||
const created: Array<{ provider: string; name: string }> = [];
|
||||
const candidates = getEligibleFreeOnboardingProviders();
|
||||
const requestedIds = ["opencode", "mimocode"];
|
||||
const requestedIds = ["opencode", "theoldllm"];
|
||||
|
||||
const first = await setupFreeProviderConnections({
|
||||
requestedIds,
|
||||
@@ -33,14 +33,14 @@ test("batch setup creates missing providers, skips existing ones, and is retry-s
|
||||
|
||||
assert.deepEqual(first.results, [
|
||||
{ providerId: "opencode", status: "skipped", reason: "already-configured" },
|
||||
{ providerId: "mimocode", status: "created", connectionId: "created-mimocode" },
|
||||
{ providerId: "theoldllm", status: "created", connectionId: "created-theoldllm" },
|
||||
]);
|
||||
assert.deepEqual(second.results, [
|
||||
{ providerId: "opencode", status: "skipped", reason: "already-configured" },
|
||||
{ providerId: "mimocode", status: "skipped", reason: "already-configured" },
|
||||
{ providerId: "theoldllm", status: "skipped", reason: "already-configured" },
|
||||
]);
|
||||
assert.deepEqual(existing, [{ provider: "opencode", name: "My customized OpenCode" }]);
|
||||
assert.deepEqual(created, [{ provider: "mimocode", name: "MiMoCode (Free)" }]);
|
||||
assert.deepEqual(created, [{ provider: "theoldllm", name: "The Old LLM (Free)" }]);
|
||||
});
|
||||
|
||||
test("batch setup rejects unknown or ineligible IDs before creating anything", async () => {
|
||||
@@ -63,13 +63,13 @@ test("batch setup rejects unknown or ineligible IDs before creating anything", a
|
||||
|
||||
test("partial failures are reported per provider and can be retried", async () => {
|
||||
const created = new Set<string>();
|
||||
let mimocodeAttempts = 0;
|
||||
let oldllmAttempts = 0;
|
||||
const input = {
|
||||
requestedIds: ["opencode", "mimocode"],
|
||||
requestedIds: ["opencode", "theoldllm"],
|
||||
candidates: getEligibleFreeOnboardingProviders(),
|
||||
listExisting: async () => [...created].map((provider) => ({ provider })),
|
||||
create: async ({ provider }: { provider: string }) => {
|
||||
if (provider === "mimocode" && mimocodeAttempts++ === 0) throw new Error("upstream detail");
|
||||
if (provider === "theoldllm" && oldllmAttempts++ === 0) throw new Error("upstream detail");
|
||||
created.add(provider);
|
||||
return { id: `created-${provider}` };
|
||||
},
|
||||
@@ -80,10 +80,10 @@ test("partial failures are reported per provider and can be retried", async () =
|
||||
|
||||
assert.deepEqual(first.results, [
|
||||
{ providerId: "opencode", status: "created", connectionId: "created-opencode" },
|
||||
{ providerId: "mimocode", status: "failed", reason: "Failed to create provider" },
|
||||
{ providerId: "theoldllm", status: "failed", reason: "Failed to create provider" },
|
||||
]);
|
||||
assert.deepEqual(retry.results, [
|
||||
{ providerId: "opencode", status: "skipped", reason: "already-configured" },
|
||||
{ providerId: "mimocode", status: "created", connectionId: "created-mimocode" },
|
||||
{ providerId: "theoldllm", status: "created", connectionId: "created-theoldllm" },
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -1,873 +0,0 @@
|
||||
import { describe, it, beforeEach, afterEach } from "node:test";
|
||||
import assert from "node:assert";
|
||||
import {
|
||||
MimocodeExecutor,
|
||||
generateFingerprint,
|
||||
MIMO_SYSTEM_MARKER,
|
||||
type AccountProxyConfig,
|
||||
} from "../../open-sse/executors/mimocode.ts";
|
||||
|
||||
const executor = new MimocodeExecutor();
|
||||
|
||||
describe("MimocodeExecutor", () => {
|
||||
it("generateFingerprint returns a 64-char hex string", () => {
|
||||
const fp = generateFingerprint();
|
||||
assert.match(fp, /^[0-9a-f]{64}$/);
|
||||
});
|
||||
|
||||
it("generateFingerprint is deterministic", () => {
|
||||
assert.strictEqual(generateFingerprint(), generateFingerprint());
|
||||
});
|
||||
|
||||
it("generateFingerprint with seed is deterministic", () => {
|
||||
assert.strictEqual(generateFingerprint("seed-a"), generateFingerprint("seed-a"));
|
||||
});
|
||||
|
||||
it("generateFingerprint with different seeds differs", () => {
|
||||
assert.notStrictEqual(generateFingerprint("seed-a"), generateFingerprint("seed-b"));
|
||||
});
|
||||
|
||||
it("buildUrl returns the free-ai chat endpoint", () => {
|
||||
const url = executor.buildUrl("mimo-auto", false);
|
||||
assert.ok(url.includes("/api/free-ai/openai/chat"));
|
||||
assert.ok(url.startsWith("https://"));
|
||||
});
|
||||
|
||||
it("buildHeaders includes X-Mimo-Source and Content-Type", () => {
|
||||
const headers = (executor as any).buildHeaders({}, true);
|
||||
assert.strictEqual(headers["Content-Type"], "application/json");
|
||||
assert.strictEqual(headers["X-Mimo-Source"], "mimocode-cli-free");
|
||||
});
|
||||
|
||||
it("buildHeaders includes Accept for streaming", () => {
|
||||
const headers = (executor as any).buildHeaders({}, true);
|
||||
assert.ok(headers["Accept"]?.includes("text/event-stream"));
|
||||
});
|
||||
|
||||
it("buildHeaders omits Accept for non-streaming", () => {
|
||||
const headers = (executor as any).buildHeaders({}, false);
|
||||
assert.ok(!headers["Accept"]?.includes("text/event-stream"));
|
||||
});
|
||||
|
||||
it("transformRequest strips model prefix", () => {
|
||||
const result = (executor as any).transformRequest(
|
||||
"mcode/mimo-auto",
|
||||
{ model: "mcode/mimo-auto", messages: [{ role: "user", content: "hi" }] },
|
||||
false
|
||||
);
|
||||
assert.strictEqual(result.model, "mimo-auto");
|
||||
});
|
||||
|
||||
it("transformRequest passes model through when no prefix", () => {
|
||||
const result = (executor as any).transformRequest(
|
||||
"mimo-auto",
|
||||
{ model: "mimo-auto", messages: [{ role: "user", content: "hi" }] },
|
||||
false
|
||||
);
|
||||
assert.strictEqual(result.model, "mimo-auto");
|
||||
});
|
||||
|
||||
// The Xiaomi free endpoint rejects requests with `403 "Illegal access"` unless the
|
||||
// body contains a recognized MiMoCode prompt signature inside a `system`-role message.
|
||||
// The executor must inject that marker so user requests pass the upstream anti-abuse gate.
|
||||
it("transformRequest injects a MiMoCode system marker when none is present", () => {
|
||||
const result = (executor as any).transformRequest(
|
||||
"mcode/mimo-auto",
|
||||
{ model: "mcode/mimo-auto", messages: [{ role: "user", content: "write a haiku" }] },
|
||||
true
|
||||
);
|
||||
assert.ok(Array.isArray(result.messages));
|
||||
const first = result.messages[0];
|
||||
assert.strictEqual(first.role, "system");
|
||||
assert.ok(
|
||||
typeof first.content === "string" && first.content.includes(MIMO_SYSTEM_MARKER),
|
||||
"first message must be a system message containing the MiMoCode marker"
|
||||
);
|
||||
});
|
||||
|
||||
it("transformRequest preserves the original user message after injection", () => {
|
||||
const result = (executor as any).transformRequest(
|
||||
"mcode/mimo-auto",
|
||||
{ model: "mcode/mimo-auto", messages: [{ role: "user", content: "write a haiku" }] },
|
||||
true
|
||||
);
|
||||
const userMsg = result.messages.find((m: any) => m.role === "user");
|
||||
assert.ok(userMsg);
|
||||
assert.strictEqual(userMsg.content, "write a haiku");
|
||||
});
|
||||
|
||||
it("transformRequest preserves a caller-provided system prompt alongside the marker", () => {
|
||||
const result = (executor as any).transformRequest(
|
||||
"mcode/mimo-auto",
|
||||
{
|
||||
model: "mcode/mimo-auto",
|
||||
messages: [
|
||||
{ role: "system", content: "You are a pirate." },
|
||||
{ role: "user", content: "hi" },
|
||||
],
|
||||
},
|
||||
true
|
||||
);
|
||||
const systemContents = result.messages
|
||||
.filter((m: any) => m.role === "system")
|
||||
.map((m: any) => m.content)
|
||||
.join("\n");
|
||||
assert.ok(systemContents.includes(MIMO_SYSTEM_MARKER), "marker present");
|
||||
assert.ok(systemContents.includes("You are a pirate."), "caller system prompt preserved");
|
||||
});
|
||||
|
||||
it("transformRequest does not duplicate the marker when already present", () => {
|
||||
const result = (executor as any).transformRequest(
|
||||
"mcode/mimo-auto",
|
||||
{
|
||||
model: "mcode/mimo-auto",
|
||||
messages: [
|
||||
{ role: "system", content: `${MIMO_SYSTEM_MARKER}\nExtra context.` },
|
||||
{ role: "user", content: "hi" },
|
||||
],
|
||||
},
|
||||
true
|
||||
);
|
||||
const count = result.messages.filter(
|
||||
(m: any) =>
|
||||
m.role === "system" &&
|
||||
typeof m.content === "string" &&
|
||||
m.content.includes(MIMO_SYSTEM_MARKER)
|
||||
).length;
|
||||
assert.strictEqual(count, 1, "marker should not be duplicated");
|
||||
});
|
||||
|
||||
it("transformRequest leaves a body without a messages array untouched", () => {
|
||||
const result = (executor as any).transformRequest(
|
||||
"mcode/mimo-auto",
|
||||
{ model: "mcode/mimo-auto", prompt: "legacy" },
|
||||
true
|
||||
);
|
||||
assert.strictEqual((result as any).messages, undefined);
|
||||
assert.strictEqual((result as any).model, "mimo-auto");
|
||||
});
|
||||
|
||||
it("returns 499 on pre-aborted signal", async () => {
|
||||
const controller = new AbortController();
|
||||
controller.abort(new Error("cancelled"));
|
||||
|
||||
const result = await executor.execute({
|
||||
model: "mimo-auto",
|
||||
body: { messages: [{ role: "user", content: "hi" }], stream: false },
|
||||
stream: false,
|
||||
signal: controller.signal,
|
||||
credentials: {},
|
||||
log: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },
|
||||
});
|
||||
|
||||
assert.strictEqual((result as any).response.status, 499);
|
||||
});
|
||||
|
||||
it("is registered in executor index", async () => {
|
||||
const { getExecutor } = await import("../../open-sse/executors/index.ts");
|
||||
const exec = getExecutor("mimocode");
|
||||
assert.ok(exec instanceof MimocodeExecutor);
|
||||
});
|
||||
|
||||
it("mcode alias works", async () => {
|
||||
const { getExecutor } = await import("../../open-sse/executors/index.ts");
|
||||
const exec = getExecutor("mcode");
|
||||
assert.ok(exec instanceof MimocodeExecutor);
|
||||
});
|
||||
});
|
||||
|
||||
describe("mimocode multi-account", () => {
|
||||
it("executor has at least one account", () => {
|
||||
const accounts = (executor as any).accounts;
|
||||
assert.ok(Array.isArray(accounts));
|
||||
assert.ok(accounts.length >= 1);
|
||||
});
|
||||
|
||||
it("each account has required fields", () => {
|
||||
const accounts = (executor as any).accounts;
|
||||
for (const acct of accounts) {
|
||||
assert.ok(typeof acct.fingerprint === "string");
|
||||
assert.ok(typeof acct.jwt === "string");
|
||||
assert.ok(typeof acct.expiresAt === "number");
|
||||
assert.ok(typeof acct.cooldownUntil === "number");
|
||||
assert.ok(typeof acct.consecutiveFails === "number");
|
||||
}
|
||||
});
|
||||
|
||||
it("pickAccount returns an account", () => {
|
||||
const acct = (executor as any).pickAccount();
|
||||
assert.ok(acct);
|
||||
assert.ok(typeof acct.fingerprint === "string");
|
||||
});
|
||||
|
||||
it("markCooldown increases consecutiveFails and sets cooldownUntil", () => {
|
||||
const acct = (executor as any).accounts[0];
|
||||
const before = acct.consecutiveFails;
|
||||
(executor as any).markCooldown(acct);
|
||||
assert.strictEqual(acct.consecutiveFails, before + 1);
|
||||
assert.ok(acct.cooldownUntil > Date.now());
|
||||
});
|
||||
|
||||
it("markSuccess resets consecutiveFails", () => {
|
||||
const acct = (executor as any).accounts[0];
|
||||
acct.consecutiveFails = 5;
|
||||
(executor as any).markSuccess(acct);
|
||||
assert.strictEqual(acct.consecutiveFails, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("mimocode provider registration", () => {
|
||||
it("provider is registered in NOAUTH_PROVIDERS", async () => {
|
||||
const { NOAUTH_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
|
||||
const provider = (NOAUTH_PROVIDERS as Record<string, any>)["mimocode"];
|
||||
assert.ok(provider);
|
||||
assert.strictEqual(provider.id, "mimocode");
|
||||
assert.strictEqual(provider.alias, "mcode");
|
||||
assert.strictEqual(provider.noAuth, true);
|
||||
assert.strictEqual(provider.hasFree, true);
|
||||
});
|
||||
|
||||
it("provider has correct service kinds", async () => {
|
||||
const { NOAUTH_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
|
||||
const provider = (NOAUTH_PROVIDERS as Record<string, any>)["mimocode"];
|
||||
assert.ok(provider.serviceKinds?.includes("llm"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("mimocode providerRegistry entry", () => {
|
||||
it("registry entry exists with correct executor", async () => {
|
||||
const { getRegistryEntry } = await import("../../open-sse/config/providerRegistry.ts");
|
||||
const entry = getRegistryEntry("mimocode");
|
||||
assert.ok(entry);
|
||||
assert.strictEqual(entry.executor, "mimocode");
|
||||
assert.strictEqual(entry.format, "openai");
|
||||
assert.strictEqual(entry.authType, "none");
|
||||
});
|
||||
|
||||
it("registry entry has mimo-auto model", async () => {
|
||||
const { getRegistryEntry } = await import("../../open-sse/config/providerRegistry.ts");
|
||||
const entry = getRegistryEntry("mimocode");
|
||||
const models = entry.models as Array<{ id: string }>;
|
||||
const mimoAuto = models.find((m) => m.id === "mimo-auto");
|
||||
assert.ok(mimoAuto);
|
||||
});
|
||||
});
|
||||
|
||||
describe("mimocode per-account proxy", () => {
|
||||
it("AccountProxyConfig type has required fields", () => {
|
||||
const config: AccountProxyConfig = {
|
||||
fingerprint: "abc123",
|
||||
proxy: { type: "http", host: "proxy.example.com", port: 8080 },
|
||||
};
|
||||
assert.strictEqual(config.fingerprint, "abc123");
|
||||
assert.strictEqual(config.proxy?.host, "proxy.example.com");
|
||||
});
|
||||
|
||||
it("default proxyUrlMap is empty", () => {
|
||||
const testExec = new MimocodeExecutor();
|
||||
const map = (testExec as any).proxyUrlMap;
|
||||
assert.ok(map instanceof Map);
|
||||
assert.strictEqual(map.size, 0);
|
||||
});
|
||||
|
||||
it("syncAccountsFromCredentials populates proxyUrlMap with correct URLs", () => {
|
||||
const testExec = new MimocodeExecutor();
|
||||
const fp1 = "fingerprint-1";
|
||||
const fp2 = "fingerprint-2";
|
||||
(testExec as any).accounts = [
|
||||
{ fingerprint: fp1, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 },
|
||||
{ fingerprint: fp2, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 },
|
||||
];
|
||||
|
||||
const credentials = {
|
||||
providerSpecificData: {
|
||||
accountProxies: [
|
||||
{ fingerprint: fp1, proxy: { type: "http", host: "p1.example.com", port: 1080 } },
|
||||
{ fingerprint: fp2, proxy: null },
|
||||
],
|
||||
},
|
||||
};
|
||||
(testExec as any).syncAccountsFromCredentials(credentials);
|
||||
|
||||
const map: Map<string, string> = (testExec as any).proxyUrlMap;
|
||||
assert.strictEqual(map.get(fp1), "http://p1.example.com:1080");
|
||||
assert.strictEqual(map.has(fp2), false);
|
||||
});
|
||||
|
||||
it("syncAccountsFromCredentials skips when accountProxies absent", () => {
|
||||
const testExec = new MimocodeExecutor();
|
||||
const mapBefore = (testExec as any).proxyUrlMap.size;
|
||||
(testExec as any).syncAccountsFromCredentials({ providerSpecificData: {} });
|
||||
assert.strictEqual((testExec as any).proxyUrlMap.size, mapBefore);
|
||||
});
|
||||
|
||||
it("syncAccountsFromCredentials adds proxyUrlMap entries for all valid proxy configs", () => {
|
||||
const testExec = new MimocodeExecutor();
|
||||
const existingFp = (testExec as any).accounts[0].fingerprint;
|
||||
(testExec as any).syncAccountsFromCredentials({
|
||||
providerSpecificData: {
|
||||
accountProxies: [
|
||||
{
|
||||
fingerprint: "nonexistent-fingerprint",
|
||||
proxy: { type: "socks5", host: "s5.example.com", port: 1080 },
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
const map: Map<string, string> = (testExec as any).proxyUrlMap;
|
||||
assert.strictEqual(
|
||||
map.has("nonexistent-fingerprint"),
|
||||
true,
|
||||
"proxyUrlMap stores all valid proxy configs"
|
||||
);
|
||||
assert.strictEqual(map.get("nonexistent-fingerprint"), "socks5://s5.example.com:1080");
|
||||
assert.strictEqual(
|
||||
map.has(existingFp),
|
||||
false,
|
||||
"existing fingerprint without proxy is not in map"
|
||||
);
|
||||
});
|
||||
|
||||
it("accounts with different proxies produce distinct URLs", () => {
|
||||
const testExec = new MimocodeExecutor();
|
||||
const fp1 = "fp-a";
|
||||
const fp2 = "fp-b";
|
||||
(testExec as any).accounts = [
|
||||
{ fingerprint: fp1, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 },
|
||||
{ fingerprint: fp2, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 },
|
||||
];
|
||||
(testExec as any).syncAccountsFromCredentials({
|
||||
providerSpecificData: {
|
||||
accountProxies: [
|
||||
{ fingerprint: fp1, proxy: { type: "http", host: "a.com", port: 8080 } },
|
||||
{ fingerprint: fp2, proxy: { type: "socks5", host: "b.com", port: 1080 } },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const map: Map<string, string> = (testExec as any).proxyUrlMap;
|
||||
assert.strictEqual(map.get(fp1), "http://a.com:8080");
|
||||
assert.strictEqual(map.get(fp2), "socks5://b.com:1080");
|
||||
});
|
||||
|
||||
it("getProxyDispatcher returns a dispatcher for known fingerprint", () => {
|
||||
const testExec = new MimocodeExecutor();
|
||||
const fp = "fp-dispatcher-test";
|
||||
(testExec as any).accounts = [
|
||||
{ fingerprint: fp, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 },
|
||||
];
|
||||
(testExec as any).syncAccountsFromCredentials({
|
||||
providerSpecificData: {
|
||||
accountProxies: [
|
||||
{ fingerprint: fp, proxy: { type: "socks5", host: "s5.test", port: 1080 } },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const dispatcher = (testExec as any).getProxyDispatcher(fp);
|
||||
assert.ok(dispatcher, "dispatcher should exist for registered fingerprint");
|
||||
});
|
||||
|
||||
it("getProxyDispatcher returns undefined for unknown fingerprint", () => {
|
||||
const testExec = new MimocodeExecutor();
|
||||
const dispatcher = (testExec as any).getProxyDispatcher("unknown-fp");
|
||||
assert.strictEqual(dispatcher, undefined);
|
||||
});
|
||||
|
||||
it("fetchWithProxy falls back to plain fetch when no proxy configured", async () => {
|
||||
const testExec = new MimocodeExecutor();
|
||||
const fp = "fp-no-proxy";
|
||||
const originalFetch = globalThis.fetch;
|
||||
let fetchCalled = false;
|
||||
globalThis.fetch = async () => {
|
||||
fetchCalled = true;
|
||||
return new Response("ok");
|
||||
};
|
||||
try {
|
||||
const resp = await (testExec as any).fetchWithProxy("https://example.com", {}, fp);
|
||||
assert.ok(fetchCalled, "plain fetch should have been called");
|
||||
assert.strictEqual(resp.status, 200);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
|
||||
it("authenticated proxy includes credentials in URL", () => {
|
||||
const testExec = new MimocodeExecutor();
|
||||
const fp = "fp-auth";
|
||||
(testExec as any).accounts = [
|
||||
{ fingerprint: fp, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 },
|
||||
];
|
||||
(testExec as any).syncAccountsFromCredentials({
|
||||
providerSpecificData: {
|
||||
accountProxies: [
|
||||
{
|
||||
fingerprint: fp,
|
||||
proxy: {
|
||||
type: "socks5",
|
||||
host: "s5.auth.com",
|
||||
port: 1080,
|
||||
username: "user",
|
||||
password: "pass",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const map: Map<string, string> = (testExec as any).proxyUrlMap;
|
||||
const url = map.get(fp);
|
||||
assert.ok(url);
|
||||
assert.ok(url.includes("user:pass@"), "URL should include encoded credentials");
|
||||
});
|
||||
|
||||
it("default port is 1080 for socks5 when not specified", () => {
|
||||
const testExec = new MimocodeExecutor();
|
||||
const fp = "fp-default-port";
|
||||
(testExec as any).accounts = [
|
||||
{ fingerprint: fp, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 },
|
||||
];
|
||||
(testExec as any).syncAccountsFromCredentials({
|
||||
providerSpecificData: {
|
||||
accountProxies: [
|
||||
{ fingerprint: fp, proxy: { type: "socks5", host: "s5.test", port: undefined } },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const map: Map<string, string> = (testExec as any).proxyUrlMap;
|
||||
assert.strictEqual(map.get(fp), "socks5://s5.test:1080");
|
||||
});
|
||||
|
||||
it("default port is 8080 for http when not specified", () => {
|
||||
const testExec = new MimocodeExecutor();
|
||||
const fp = "fp-http-default";
|
||||
(testExec as any).accounts = [
|
||||
{ fingerprint: fp, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 },
|
||||
];
|
||||
(testExec as any).syncAccountsFromCredentials({
|
||||
providerSpecificData: {
|
||||
accountProxies: [
|
||||
{ fingerprint: fp, proxy: { type: "http", host: "h.test", port: undefined } },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const map: Map<string, string> = (testExec as any).proxyUrlMap;
|
||||
assert.strictEqual(map.get(fp), "http://h.test:8080");
|
||||
});
|
||||
|
||||
it("proxy URL map updates correctly on re-sync", () => {
|
||||
const testExec = new MimocodeExecutor();
|
||||
const fp = "fp-re-sync";
|
||||
(testExec as any).accounts = [
|
||||
{ fingerprint: fp, jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 },
|
||||
];
|
||||
|
||||
(testExec as any).syncAccountsFromCredentials({
|
||||
providerSpecificData: {
|
||||
accountProxies: [
|
||||
{ fingerprint: fp, proxy: { type: "http", host: "first.proxy", port: 8080 } },
|
||||
],
|
||||
},
|
||||
});
|
||||
assert.strictEqual((testExec as any).proxyUrlMap.get(fp), "http://first.proxy:8080");
|
||||
|
||||
(testExec as any).syncAccountsFromCredentials({
|
||||
providerSpecificData: {
|
||||
accountProxies: [
|
||||
{ fingerprint: fp, proxy: { type: "socks5", host: "second.proxy", port: 1080 } },
|
||||
],
|
||||
},
|
||||
});
|
||||
assert.strictEqual((testExec as any).proxyUrlMap.get(fp), "socks5://second.proxy:1080");
|
||||
});
|
||||
});
|
||||
|
||||
// #2101/#4976 regression guard: a 400 from MiMoCode must be classified by body text
|
||||
// before deciding whether to rotate accounts. A rate-limit-style 400 (throttling
|
||||
// disguised as a 400, #4976) is rotation-worthy; a genuinely malformed 400 (#2101)
|
||||
// must fail fast on the FIRST account instead of being retried identically on every
|
||||
// account (which would waste N round-trips, cooldown every account, and hide the
|
||||
// real upstream diagnostic behind a generic "all accounts exhausted" error).
|
||||
interface TestAccountState {
|
||||
fingerprint: string;
|
||||
jwt: string;
|
||||
expiresAt: number;
|
||||
cooldownUntil: number;
|
||||
consecutiveFails: number;
|
||||
proxy?: unknown;
|
||||
}
|
||||
|
||||
interface ExecutorAccountAccess {
|
||||
accounts: TestAccountState[];
|
||||
nextAccountIdx: number;
|
||||
}
|
||||
|
||||
function accountAccess(exec: MimocodeExecutor): ExecutorAccountAccess {
|
||||
return exec as unknown as ExecutorAccountAccess;
|
||||
}
|
||||
|
||||
describe("mimocode 400 classification (#2101/#4976)", () => {
|
||||
function makeJwt(): string {
|
||||
const header = Buffer.from(JSON.stringify({ alg: "none" })).toString("base64url");
|
||||
const payload = Buffer.from(
|
||||
JSON.stringify({ exp: Math.floor(Date.now() / 1000) + 3600 })
|
||||
).toString("base64url");
|
||||
return `${header}.${payload}.sig`;
|
||||
}
|
||||
|
||||
function twoAccountExecutor(): MimocodeExecutor {
|
||||
const exec = new MimocodeExecutor();
|
||||
const access = accountAccess(exec);
|
||||
access.accounts = [
|
||||
{ fingerprint: "acct-a", jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 },
|
||||
{ fingerprint: "acct-b", jwt: "", expiresAt: 0, cooldownUntil: 0, consecutiveFails: 0 },
|
||||
];
|
||||
access.nextAccountIdx = 0;
|
||||
return exec;
|
||||
}
|
||||
|
||||
it("rotates to the next account on a rate-limit-text 400 (#4976)", async () => {
|
||||
const testExec = twoAccountExecutor();
|
||||
let chatCalls = 0;
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = (async (url: unknown) => {
|
||||
const urlStr = String(url);
|
||||
if (urlStr.includes("/api/free-ai/bootstrap")) {
|
||||
return new Response(JSON.stringify({ jwt: makeJwt() }), { status: 200 });
|
||||
}
|
||||
if (urlStr.includes("/api/free-ai/openai/chat")) {
|
||||
chatCalls++;
|
||||
if (chatCalls === 1) {
|
||||
// MiMoCode's non-standard rate-limit signal on a 400 status (#4976).
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
error: { message: "Detected high-frequency non-compliant requests from you." },
|
||||
}),
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
return new Response(JSON.stringify({ id: "ok", choices: [] }), { status: 200 });
|
||||
}
|
||||
throw new Error(`unexpected fetch: ${urlStr}`);
|
||||
}) as typeof fetch;
|
||||
|
||||
try {
|
||||
const result = await testExec.execute({
|
||||
model: "mimo-auto",
|
||||
body: { messages: [{ role: "user", content: "hi" }], stream: false },
|
||||
stream: false,
|
||||
signal: null,
|
||||
credentials: {},
|
||||
log: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },
|
||||
});
|
||||
|
||||
assert.strictEqual(chatCalls, 2, "should retry on the next account after the 400");
|
||||
assert.strictEqual(result.response.status, 200);
|
||||
const acctA = accountAccess(testExec).accounts[0];
|
||||
assert.ok(acctA.cooldownUntil > Date.now(), "first account should be in cooldown");
|
||||
assert.strictEqual(acctA.consecutiveFails, 1);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
|
||||
it("fails fast without rotating on a malformed/generic 400 (#2101)", async () => {
|
||||
const testExec = twoAccountExecutor();
|
||||
let chatCalls = 0;
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = (async (url: unknown) => {
|
||||
const urlStr = String(url);
|
||||
if (urlStr.includes("/api/free-ai/bootstrap")) {
|
||||
return new Response(JSON.stringify({ jwt: makeJwt() }), { status: 200 });
|
||||
}
|
||||
if (urlStr.includes("/api/free-ai/openai/chat")) {
|
||||
chatCalls++;
|
||||
return new Response(
|
||||
JSON.stringify({ error: { message: "Invalid field: foo is not a recognized field" } }),
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
throw new Error(`unexpected fetch: ${urlStr}`);
|
||||
}) as typeof fetch;
|
||||
|
||||
try {
|
||||
const result = await testExec.execute({
|
||||
model: "mimo-auto",
|
||||
body: { messages: [{ role: "user", content: "hi" }], stream: false },
|
||||
stream: false,
|
||||
signal: null,
|
||||
credentials: {},
|
||||
log: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },
|
||||
});
|
||||
|
||||
assert.strictEqual(chatCalls, 1, "must NOT rotate to another account on a malformed 400");
|
||||
const acctA = accountAccess(testExec).accounts[0];
|
||||
assert.strictEqual(acctA.cooldownUntil, 0, "malformed 400 must not trigger cooldown");
|
||||
assert.strictEqual(acctA.consecutiveFails, 0);
|
||||
|
||||
const response = result.response;
|
||||
assert.strictEqual(response.status, 400);
|
||||
const parsed = (await response.json()) as { error: { message: string; code?: string } };
|
||||
assert.notStrictEqual(
|
||||
parsed.error.code,
|
||||
"NO_ACCOUNTS",
|
||||
"must surface the real upstream 400, not a generic exhaustion error"
|
||||
);
|
||||
assert.ok(
|
||||
parsed.error.message.toLowerCase().includes("invalid field"),
|
||||
`expected the real upstream diagnostic in the error message, got: ${parsed.error.message}`
|
||||
);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("mimocode network-error rotation (parity with OpencodeExecutor)", () => {
|
||||
function makeJwt(): string {
|
||||
const header = Buffer.from(JSON.stringify({ alg: "none" })).toString("base64url");
|
||||
const payload = Buffer.from(
|
||||
JSON.stringify({ exp: Math.floor(Date.now() / 1000) + 3600 })
|
||||
).toString("base64url");
|
||||
return `${header}.${payload}.sig`;
|
||||
}
|
||||
|
||||
function twoAccountExecutor(proxies: [unknown, unknown]): MimocodeExecutor {
|
||||
const exec = new MimocodeExecutor();
|
||||
const access = accountAccess(exec);
|
||||
access.accounts = [
|
||||
{
|
||||
fingerprint: "acct-a",
|
||||
jwt: "",
|
||||
expiresAt: 0,
|
||||
cooldownUntil: 0,
|
||||
consecutiveFails: 0,
|
||||
proxy: proxies[0],
|
||||
},
|
||||
{
|
||||
fingerprint: "acct-b",
|
||||
jwt: "",
|
||||
expiresAt: 0,
|
||||
cooldownUntil: 0,
|
||||
consecutiveFails: 0,
|
||||
proxy: proxies[1],
|
||||
},
|
||||
] as TestAccountState[];
|
||||
access.nextAccountIdx = 0;
|
||||
return exec;
|
||||
}
|
||||
|
||||
const A_PROXY = { type: "http", host: "127.0.0.1", port: 8080 };
|
||||
const B_PROXY = { type: "http", host: "127.0.0.1", port: 8081 };
|
||||
|
||||
it("rotates to the next account on a network throw when the failed account has a dedicated proxy", async () => {
|
||||
const testExec = twoAccountExecutor([A_PROXY, B_PROXY]);
|
||||
// Force both dispatch legs (bootstrap + chat) through the plain `fetch()`
|
||||
// fallback instead of a real undici proxy dispatcher — this test exercises
|
||||
// the rotation DECISION (account.proxy is configured → rotate), not actual
|
||||
// proxy network I/O, which has its own dedicated dispatcher tests below.
|
||||
(testExec as unknown as { getProxyDispatcher: () => undefined }).getProxyDispatcher = () =>
|
||||
undefined;
|
||||
let chatCalls = 0;
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = (async (url: unknown) => {
|
||||
const urlStr = String(url);
|
||||
if (urlStr.includes("/api/free-ai/bootstrap")) {
|
||||
return new Response(JSON.stringify({ jwt: makeJwt() }), { status: 200 });
|
||||
}
|
||||
if (urlStr.includes("/api/free-ai/openai/chat")) {
|
||||
chatCalls++;
|
||||
if (chatCalls === 1) throw new Error("ECONNRESET");
|
||||
return new Response(JSON.stringify({ id: "ok", choices: [] }), { status: 200 });
|
||||
}
|
||||
throw new Error(`unexpected fetch: ${urlStr}`);
|
||||
}) as typeof fetch;
|
||||
|
||||
const warnCalls: string[] = [];
|
||||
try {
|
||||
const result = await testExec.execute({
|
||||
model: "mimo-auto",
|
||||
body: { messages: [{ role: "user", content: "hi" }], stream: false },
|
||||
stream: false,
|
||||
signal: null,
|
||||
credentials: {
|
||||
providerSpecificData: {
|
||||
fingerprints: ["acct-a", "acct-b"],
|
||||
accountProxies: [
|
||||
{ fingerprint: "acct-a", proxy: A_PROXY },
|
||||
{ fingerprint: "acct-b", proxy: B_PROXY },
|
||||
],
|
||||
},
|
||||
},
|
||||
log: {
|
||||
debug: () => {},
|
||||
info: () => {},
|
||||
warn: (_tag: unknown, msg: string) => warnCalls.push(msg),
|
||||
error: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(chatCalls, 2, "should retry on the next account after the throw");
|
||||
assert.strictEqual(result.response.status, 200);
|
||||
const acctA = accountAccess(testExec).accounts[0];
|
||||
assert.ok(acctA.cooldownUntil > Date.now(), "account with a dedicated proxy must cool down");
|
||||
assert.ok(
|
||||
warnCalls.some((m) => /network error/i.test(m)),
|
||||
`expected a "network error" warn log; got=${JSON.stringify(warnCalls)}`
|
||||
);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
|
||||
describe("NETWORK_ROTATION_SHARED_EGRESS_GUARD", () => {
|
||||
const FLAG = "NETWORK_ROTATION_SHARED_EGRESS_GUARD";
|
||||
let originalEnvValue: string | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
originalEnvValue = process.env[FLAG];
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (originalEnvValue === undefined) delete process.env[FLAG];
|
||||
else process.env[FLAG] = originalEnvValue;
|
||||
});
|
||||
|
||||
it("rotates to a proxied account after a proxy-less account throws (mixed fleet, guard on by default)", async () => {
|
||||
const testExec = twoAccountExecutor([null, B_PROXY]);
|
||||
// Force both dispatch legs through the plain `fetch()` fallback instead
|
||||
// of a real undici proxy dispatcher — this test exercises the rotation
|
||||
// DECISION, not actual proxy network I/O.
|
||||
(testExec as unknown as { getProxyDispatcher: () => undefined }).getProxyDispatcher = () =>
|
||||
undefined;
|
||||
let chatCalls = 0;
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = (async (url: unknown) => {
|
||||
const urlStr = String(url);
|
||||
if (urlStr.includes("/api/free-ai/bootstrap")) {
|
||||
return new Response(JSON.stringify({ jwt: makeJwt() }), { status: 200 });
|
||||
}
|
||||
if (urlStr.includes("/api/free-ai/openai/chat")) {
|
||||
chatCalls++;
|
||||
if (chatCalls === 1) throw new Error("ETIMEDOUT");
|
||||
return new Response(JSON.stringify({ id: "ok", choices: [] }), { status: 200 });
|
||||
}
|
||||
throw new Error(`unexpected fetch: ${urlStr}`);
|
||||
}) as typeof fetch;
|
||||
|
||||
try {
|
||||
const result = await testExec.execute({
|
||||
model: "mimo-auto",
|
||||
body: { messages: [{ role: "user", content: "hi" }], stream: false },
|
||||
stream: false,
|
||||
signal: null,
|
||||
credentials: {
|
||||
providerSpecificData: {
|
||||
fingerprints: ["acct-a", "acct-b"],
|
||||
accountProxies: [{ fingerprint: "acct-b", proxy: B_PROXY }],
|
||||
},
|
||||
},
|
||||
log: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },
|
||||
});
|
||||
|
||||
assert.strictEqual(chatCalls, 2, "the proxied account (B) must still be tried");
|
||||
assert.strictEqual(result.response.status, 200);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
|
||||
it("makes a single real network call when no account has a configured proxy (guard on by default)", async () => {
|
||||
const testExec = twoAccountExecutor([null, null]);
|
||||
let chatCalls = 0;
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = (async (url: unknown) => {
|
||||
const urlStr = String(url);
|
||||
if (urlStr.includes("/api/free-ai/bootstrap")) {
|
||||
return new Response(JSON.stringify({ jwt: makeJwt() }), { status: 200 });
|
||||
}
|
||||
if (urlStr.includes("/api/free-ai/openai/chat")) {
|
||||
chatCalls++;
|
||||
throw new Error("ETIMEDOUT");
|
||||
}
|
||||
throw new Error(`unexpected fetch: ${urlStr}`);
|
||||
}) as typeof fetch;
|
||||
|
||||
try {
|
||||
const result = await testExec.execute({
|
||||
model: "mimo-auto",
|
||||
body: { messages: [{ role: "user", content: "hi" }], stream: false },
|
||||
stream: false,
|
||||
signal: null,
|
||||
credentials: {},
|
||||
log: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
chatCalls,
|
||||
1,
|
||||
"remaining proxy-less accounts must be skipped without a network call once the shared egress is known down"
|
||||
);
|
||||
assert.strictEqual(result.response.status, 502);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
|
||||
it("fails fast without rotating when the guard is disabled (legacy behavior)", async () => {
|
||||
process.env[FLAG] = "false";
|
||||
const testExec = twoAccountExecutor([null, null]);
|
||||
let chatCalls = 0;
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = (async (url: unknown) => {
|
||||
const urlStr = String(url);
|
||||
if (urlStr.includes("/api/free-ai/bootstrap")) {
|
||||
return new Response(JSON.stringify({ jwt: makeJwt() }), { status: 200 });
|
||||
}
|
||||
if (urlStr.includes("/api/free-ai/openai/chat")) {
|
||||
chatCalls++;
|
||||
throw new Error("ETIMEDOUT");
|
||||
}
|
||||
throw new Error(`unexpected fetch: ${urlStr}`);
|
||||
}) as typeof fetch;
|
||||
|
||||
const warnCalls: string[] = [];
|
||||
try {
|
||||
const result = await testExec.execute({
|
||||
model: "mimo-auto",
|
||||
body: { messages: [{ role: "user", content: "hi" }], stream: false },
|
||||
stream: false,
|
||||
signal: null,
|
||||
credentials: {},
|
||||
log: {
|
||||
debug: () => {},
|
||||
info: () => {},
|
||||
warn: (_tag: unknown, msg: string) => warnCalls.push(msg),
|
||||
error: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
chatCalls,
|
||||
1,
|
||||
"must NOT retry against another account sharing the same egress"
|
||||
);
|
||||
const acctA = accountAccess(testExec).accounts[0];
|
||||
assert.strictEqual(
|
||||
acctA.cooldownUntil,
|
||||
0,
|
||||
"an account without a dedicated proxy must not be cooled down for a shared-egress failure"
|
||||
);
|
||||
assert.strictEqual(result.response.status, 502);
|
||||
assert.ok(
|
||||
warnCalls.some((m) => /network error/i.test(m) && /not rotating/i.test(m)),
|
||||
`expected a "network error … not rotating" warn log; got=${JSON.stringify(warnCalls)}`
|
||||
);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,130 +0,0 @@
|
||||
/**
|
||||
* Xiaomi MiMo vision capability — robust override against a wrong synced `attachment`.
|
||||
*
|
||||
* Per Xiaomi's official docs (mimo.mi.com .../multimodal-understanding/image-understanding)
|
||||
* ONLY `mimo-v2.5` and `mimo-v2-omni` accept image input. The `*-pro` chat models
|
||||
* (`mimo-v2.5-pro`, `mimo-v2-pro`) and `mimo-v2-flash` are TEXT-ONLY.
|
||||
*
|
||||
* models.dev mislabels `mimo-v2.5-pro` as attachment-capable (hermes-agent#18884),
|
||||
* and `resolveVisionCapability` lets a synced `attachment:true` win first — which would
|
||||
* route an image request to a blind model (the #4071 failure mode). A hard override
|
||||
* keyed on the documented text-only ids must beat the synced verdict.
|
||||
*
|
||||
* The discriminator is `attachment`: a synced row sets `attachment` from the seeded
|
||||
* value, while the override forces `supportsVision:false` regardless. So a row seeded
|
||||
* with `attachment:true` whose `supportsVision` still resolves `false` proves the
|
||||
* override — not the synced path — produced the verdict.
|
||||
*/
|
||||
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 TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-mimo-vision-"));
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
|
||||
const core = await import("../../src/lib/db/core.ts");
|
||||
const modelsDevSync = await import("../../src/lib/modelsDevSync.ts");
|
||||
const modelCapabilities = await import("../../src/lib/modelCapabilities.ts");
|
||||
|
||||
function buildCapability(overrides = {}) {
|
||||
return {
|
||||
tool_call: null,
|
||||
reasoning: null,
|
||||
attachment: null,
|
||||
structured_output: null,
|
||||
temperature: null,
|
||||
modalities_input: "[]",
|
||||
modalities_output: "[]",
|
||||
knowledge_cutoff: null,
|
||||
release_date: null,
|
||||
last_updated: null,
|
||||
status: null,
|
||||
family: null,
|
||||
open_weights: null,
|
||||
limit_context: null,
|
||||
limit_input: null,
|
||||
limit_output: null,
|
||||
interleaved_field: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function resetStorage() {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
// Mirror the WRONG models.dev `xiaomi-mimo` keying: the text-only `*-pro` chat models
|
||||
// carry attachment:true (the upstream mislabel), while the genuinely multimodal
|
||||
// `mimo-v2.5` / `mimo-v2-omni` correctly carry attachment:true too.
|
||||
function seedMimoCapabilities() {
|
||||
modelsDevSync.saveModelsDevCapabilities({
|
||||
"xiaomi-mimo": {
|
||||
"mimo-v2.5-pro": buildCapability({
|
||||
attachment: true, // upstream mislabel — must be overridden to text-only
|
||||
modalities_input: JSON.stringify(["text", "image"]),
|
||||
modalities_output: JSON.stringify(["text"]),
|
||||
status: "stable",
|
||||
}),
|
||||
"mimo-v2-pro": buildCapability({
|
||||
attachment: true, // upstream mislabel — must be overridden to text-only
|
||||
modalities_input: JSON.stringify(["text", "image"]),
|
||||
modalities_output: JSON.stringify(["text"]),
|
||||
status: "stable",
|
||||
}),
|
||||
"mimo-v2.5": buildCapability({
|
||||
attachment: true, // genuinely multimodal — must stay vision-capable
|
||||
modalities_input: JSON.stringify(["text", "image", "audio", "video"]),
|
||||
modalities_output: JSON.stringify(["text"]),
|
||||
status: "stable",
|
||||
}),
|
||||
"mimo-v2-omni": buildCapability({
|
||||
attachment: true, // genuinely multimodal — must stay vision-capable
|
||||
modalities_input: JSON.stringify(["text", "image", "audio", "video"]),
|
||||
modalities_output: JSON.stringify(["text"]),
|
||||
status: "stable",
|
||||
}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
test.beforeEach(() => {
|
||||
resetStorage();
|
||||
});
|
||||
|
||||
test.after(() => {
|
||||
core.resetDbInstance();
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
test("mimo-v2.5-pro stays text-only even when models.dev says attachment:true", () => {
|
||||
seedMimoCapabilities();
|
||||
const pro = modelCapabilities.getResolvedModelCapabilities("xiaomi-mimo/mimo-v2.5-pro");
|
||||
// attachment is the seeded synced value, but the override forces vision false.
|
||||
assert.equal(pro.attachment, true, "synced attachment row is present (proves override, not absence)");
|
||||
assert.equal(pro.supportsVision, false, "text-only override must beat the wrong synced attachment");
|
||||
});
|
||||
|
||||
test("mimo-v2-pro stays text-only even when models.dev says attachment:true", () => {
|
||||
seedMimoCapabilities();
|
||||
const pro = modelCapabilities.getResolvedModelCapabilities("xiaomi-mimo/mimo-v2-pro");
|
||||
assert.equal(pro.supportsVision, false, "text-only override must beat the wrong synced attachment");
|
||||
});
|
||||
|
||||
test("genuinely multimodal mimo models keep vision (override is precise, not broad)", () => {
|
||||
seedMimoCapabilities();
|
||||
const v25 = modelCapabilities.getResolvedModelCapabilities("xiaomi-mimo/mimo-v2.5");
|
||||
const omni = modelCapabilities.getResolvedModelCapabilities("xiaomi-mimo/mimo-v2-omni");
|
||||
assert.equal(v25.supportsVision, true, "mimo-v2.5 is multimodal — must NOT be caught by the override");
|
||||
assert.equal(omni.supportsVision, true, "mimo-v2-omni is multimodal — must NOT be caught by the override");
|
||||
});
|
||||
|
||||
test("the bare (unqualified) text-only id is also overridden", () => {
|
||||
seedMimoCapabilities();
|
||||
// No provider prefix — exercises the `^...$` branch of the override regex.
|
||||
const bare = modelCapabilities.getResolvedModelCapabilities("mimo-v2.5-pro");
|
||||
assert.equal(bare.supportsVision, false, "bare text-only id must also be overridden");
|
||||
});
|
||||
@@ -17,7 +17,6 @@ import { hasSpecializedExecutor } from "../../open-sse/executors/index.ts";
|
||||
for (const provider of [
|
||||
"theoldllm",
|
||||
"chipotle",
|
||||
"mimocode",
|
||||
"opencode",
|
||||
"duckduckgo-web",
|
||||
"veoaifree-web",
|
||||
|
||||
@@ -4,20 +4,16 @@ import { getUnsupportedParams } from "../../open-sse/config/providerRegistry.ts"
|
||||
|
||||
// Regression guard for `TypeError: entry.models is not iterable`.
|
||||
//
|
||||
// A registry entry can legitimately have no static model catalogue — e.g. the
|
||||
// `mimocode` proxy provider, whose `models` is `undefined`. The byModelId map
|
||||
// builder already tolerates this (`if (entry.models && entry.models.length > 0)`),
|
||||
// A registry entry can legitimately have no static model catalogue — e.g. a
|
||||
// proxy provider whose `models` is `undefined`. The byModelId map builder
|
||||
// already tolerates this (`if (entry.models && entry.models.length > 0)`),
|
||||
// but `getUnsupportedParams` had two unguarded accesses:
|
||||
// - `ensureUnsupportedParamsPopulated()` iterated `entry.models` for EVERY entry,
|
||||
// - the per-provider lookup did `entry?.models.find(...)`.
|
||||
// Either one threw on the first call once a model-less entry existed, which made
|
||||
// `handleChatCore` report "All models failed" for unrelated requests.
|
||||
|
||||
test("getUnsupportedParams does not throw when a registry entry has no models (mimocode regression)", () => {
|
||||
test("getUnsupportedParams does not throw when a registry entry has no models", () => {
|
||||
// This call triggers ensureUnsupportedParamsPopulated() which walks ALL entries.
|
||||
assert.doesNotThrow(() => getUnsupportedParams("openai", "gpt-4o"));
|
||||
});
|
||||
|
||||
test("getUnsupportedParams returns [] for a model-less proxy provider", () => {
|
||||
assert.deepEqual(getUnsupportedParams("mimocode", "anything"), []);
|
||||
});
|
||||
|
||||
@@ -149,10 +149,10 @@ test("BLOCKS: a dead no-auth provider proxy assignment", async () => {
|
||||
port: 9005,
|
||||
});
|
||||
await proxiesDb.updateProxy(proxy!.id, { status: "inactive" });
|
||||
await proxiesDb.assignProxyToScope("provider", "mimocode", proxy!.id);
|
||||
await proxiesDb.assignProxyToScope("provider", "opencode", proxy!.id);
|
||||
|
||||
assert.equal(
|
||||
proxiesDb.hasBlockingProxyAssignment("noauth", "mimocode"),
|
||||
proxiesDb.hasBlockingProxyAssignment("noauth", "opencode"),
|
||||
true,
|
||||
"a dead no-auth provider proxy must block instead of allowing direct egress"
|
||||
);
|
||||
|
||||
@@ -20,29 +20,29 @@ test.after(async () => {
|
||||
else process.env.INITIAL_PASSWORD = ORIGINAL_INITIAL_PASSWORD;
|
||||
});
|
||||
|
||||
test("#6272: resolveProxyForConnection('noauth', ...) honors a provider-level proxy assigned to 'mimocode'", async () => {
|
||||
test("#6272: resolveProxyForConnection('noauth', ...) honors a provider-level proxy assigned to 'opencode'", async () => {
|
||||
core.getDbInstance();
|
||||
const proxy = { type: "http", host: "127.0.0.1", port: 8888 };
|
||||
|
||||
// Reporter's second symptom: "same thing happen when i set the proxy directly
|
||||
// in the provider menu" -> assign a provider-scoped proxy to the mimocode
|
||||
// provider id, the way Settings -> Providers -> mimocode would persist it.
|
||||
await settingsDb.setProxyForLevel("provider", "mimocode", proxy);
|
||||
// in the provider menu" -> assign a provider-scoped proxy to the opencode
|
||||
// provider id, the way Settings -> Providers -> opencode would persist it.
|
||||
await settingsDb.setProxyForLevel("provider", "opencode", proxy);
|
||||
|
||||
const resolved = await settingsDb.resolveProxyForConnection("noauth", undefined);
|
||||
|
||||
assert.equal(
|
||||
resolved?.proxy?.host,
|
||||
"127.0.0.1",
|
||||
`expected the mimocode provider-level proxy to be honored, got level=${resolved?.level} proxy=${JSON.stringify(resolved?.proxy)}`
|
||||
`expected the opencode provider-level proxy to be honored, got level=${resolved?.level} proxy=${JSON.stringify(resolved?.proxy)}`
|
||||
);
|
||||
assert.equal(resolved?.level, "provider");
|
||||
assert.equal(resolved?.levelId, "mimocode");
|
||||
assert.equal(resolved?.levelId, "opencode");
|
||||
});
|
||||
|
||||
test("control: resolveProxyForConnection('noauth', ...) still honors the GLOBAL proxy when no no-auth provider proxy is set", async () => {
|
||||
core.getDbInstance();
|
||||
await settingsDb.deleteProxyForLevel("provider", "mimocode");
|
||||
await settingsDb.deleteProxyForLevel("provider", "opencode");
|
||||
const proxy = { type: "http", host: "10.0.0.1", port: 9999 };
|
||||
await settingsDb.setProxyForLevel("global", null, proxy);
|
||||
|
||||
@@ -54,7 +54,7 @@ test("control: resolveProxyForConnection('noauth', ...) still honors the GLOBAL
|
||||
test("resolveProxyForConnection keeps provider-level no-auth proxies isolated", async () => {
|
||||
core.getDbInstance();
|
||||
await settingsDb.deleteProxyForLevel("global", null);
|
||||
await settingsDb.setProxyForLevel("provider", "mimocode", {
|
||||
await settingsDb.setProxyForLevel("provider", "opencode", {
|
||||
type: "http",
|
||||
host: "127.0.0.2",
|
||||
port: 8889,
|
||||
@@ -65,16 +65,16 @@ test("resolveProxyForConnection keeps provider-level no-auth proxies isolated",
|
||||
port: 8890,
|
||||
});
|
||||
|
||||
const mimocode = await settingsDb.resolveProxyForConnection("noauth", undefined, "mimocode");
|
||||
const opencode = await settingsDb.resolveProxyForConnection("noauth", undefined, "opencode");
|
||||
const theOldLlm = await settingsDb.resolveProxyForConnection("noauth", undefined, "theoldllm");
|
||||
|
||||
assert.equal(mimocode?.proxy?.host, "127.0.0.2");
|
||||
assert.equal(opencode?.proxy?.host, "127.0.0.2");
|
||||
assert.equal(theOldLlm?.proxy?.host, "127.0.0.3");
|
||||
});
|
||||
|
||||
test("safeResolveProxy keeps the synthetic no-auth connection provider-specific", async () => {
|
||||
core.getDbInstance();
|
||||
await settingsDb.setProxyForLevel("provider", "mimocode", {
|
||||
await settingsDb.setProxyForLevel("provider", "opencode", {
|
||||
type: "http",
|
||||
host: "127.0.0.4",
|
||||
port: 8891,
|
||||
@@ -85,9 +85,9 @@ test("safeResolveProxy keeps the synthetic no-auth connection provider-specific"
|
||||
port: 8892,
|
||||
});
|
||||
|
||||
const mimocode = await safeResolveProxy("noauth", undefined, "mimocode");
|
||||
const opencode = await safeResolveProxy("noauth", undefined, "opencode");
|
||||
const theOldLlm = await safeResolveProxy("noauth", undefined, "theoldllm");
|
||||
|
||||
assert.equal(mimocode?.proxy?.host, "127.0.0.4");
|
||||
assert.equal(opencode?.proxy?.host, "127.0.0.4");
|
||||
assert.equal(theOldLlm?.proxy?.host, "127.0.0.5");
|
||||
});
|
||||
|
||||
@@ -165,7 +165,7 @@ test("integration: 400 with rate-limit text still falls over under default confi
|
||||
"Detected high-frequency non-compliant requests from you.",
|
||||
0,
|
||||
null,
|
||||
"mimocode"
|
||||
"opencode"
|
||||
);
|
||||
assert.equal(res.shouldFallback, true);
|
||||
clearEnv();
|
||||
|
||||
@@ -2,7 +2,6 @@ import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
const { OpencodeExecutor } = await import("../../open-sse/executors/opencode.ts");
|
||||
const { MimocodeExecutor } = await import("../../open-sse/executors/mimocode.ts");
|
||||
|
||||
/**
|
||||
* Behavioral guards for the three type-only fixes in the TS 7 executor slice
|
||||
@@ -78,68 +77,3 @@ describe("OpencodeExecutor — tools truncation survives the narrowing fix", ()
|
||||
});
|
||||
});
|
||||
|
||||
describe("MimocodeExecutor — AccountState.proxy is always present (#3837/#5521)", () => {
|
||||
const FP = "fingerprint-1";
|
||||
|
||||
function accountsOf(exec: unknown): Array<Record<string, unknown>> {
|
||||
return (exec as { accounts: Array<Record<string, unknown>> }).accounts;
|
||||
}
|
||||
|
||||
function sync(exec: unknown, credentials: unknown): void {
|
||||
(exec as { syncAccountsFromCredentials(c: unknown): void }).syncAccountsFromCredentials(
|
||||
credentials
|
||||
);
|
||||
}
|
||||
|
||||
it("defaults proxy to null — not undefined — when no accountProxies are configured", () => {
|
||||
const exec = new MimocodeExecutor();
|
||||
accountsOf(exec).length = 0;
|
||||
accountsOf(exec).push({
|
||||
fingerprint: FP,
|
||||
jwt: "",
|
||||
expiresAt: 0,
|
||||
cooldownUntil: 0,
|
||||
consecutiveFails: 0,
|
||||
});
|
||||
|
||||
sync(exec, { providerSpecificData: {} });
|
||||
|
||||
const account = accountsOf(exec)[0];
|
||||
assert.ok("proxy" in account, "every account must expose a proxy key");
|
||||
assert.equal(account.proxy, null, "unconfigured proxy is null, never undefined");
|
||||
});
|
||||
|
||||
it("resolves a configured proxy onto the matching account", () => {
|
||||
const exec = new MimocodeExecutor();
|
||||
accountsOf(exec).length = 0;
|
||||
accountsOf(exec).push({
|
||||
fingerprint: FP,
|
||||
jwt: "",
|
||||
expiresAt: 0,
|
||||
cooldownUntil: 0,
|
||||
consecutiveFails: 0,
|
||||
});
|
||||
|
||||
const proxy = { type: "http", host: "p1.example.com", port: 1080 };
|
||||
sync(exec, { providerSpecificData: { accountProxies: [{ fingerprint: FP, proxy }] } });
|
||||
|
||||
assert.deepEqual(accountsOf(exec)[0].proxy, proxy);
|
||||
});
|
||||
|
||||
it("clears a previously-resolved proxy back to null when config drops it", () => {
|
||||
const exec = new MimocodeExecutor();
|
||||
accountsOf(exec).length = 0;
|
||||
accountsOf(exec).push({
|
||||
fingerprint: FP,
|
||||
jwt: "",
|
||||
expiresAt: 0,
|
||||
cooldownUntil: 0,
|
||||
consecutiveFails: 0,
|
||||
proxy: { type: "http", host: "stale.example.com", port: 8080 },
|
||||
});
|
||||
|
||||
sync(exec, { providerSpecificData: { accountProxies: [] } });
|
||||
|
||||
assert.equal(accountsOf(exec)[0].proxy, null, "a removed proxy must not linger on the account");
|
||||
});
|
||||
});
|
||||
|
||||