Compare commits

..

1 Commits

Author SHA1 Message Date
Markus Hartung
5951b64713 docs(quality): document how the CodeQL ratchet refreshes and how to tighten it 2026-09-03 11:45:34 -03:00
230 changed files with 873 additions and 6940 deletions

View File

@@ -1290,7 +1290,7 @@ GITHUB_OAUTH_CLIENT_ID=Iv1.b507a08c87ecfe98
# Used by: open-sse/executors/base.ts — buildHeaders() dynamic lookup.
# Update these when providers release new CLI versions to avoid blocks.
CLAUDE_USER_AGENT="claude-cli/2.1.258 (external, cli)"
CLAUDE_USER_AGENT="claude-cli/2.1.219 (external, cli)"
# Disable the deterministic tool-name cloak applied on both Anthropic-bound paths
# (executors/base.ts native OAuth + executors/cliproxyapi.ts CLIProxyAPI) —

View File

@@ -46,7 +46,7 @@ Repository map and Reference Documentation sections below.
## Project at a Glance
**OmniRoute** — unified AI proxy/router. One endpoint, 356 LLM providers, auto-fallback.
**OmniRoute** — unified AI proxy/router. One endpoint, 355 LLM providers, auto-fallback.
| Layer | Location | Purpose |
| ------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -56,7 +56,7 @@ Repository map and Reference Documentation sections below.
| Translators | `open-sse/translator/` | Format conversion (OpenAI↔Claude↔Gemini) |
| Transformer | `open-sse/transformer/` | Responses API ↔ Chat Completions |
| Services | `open-sse/services/` | Combo routing, rate limits, caching, etc |
| Database | `src/lib/db/` | SQLite domain modules (169 migrations) |
| Database | `src/lib/db/` | SQLite domain modules (168 migrations) |
| Domain/Policy | `src/domain/` | Policy engine, cost rules, fallback logic |
| MCP Server | `open-sse/mcp-server/` | 110 tools (45 canonical + memory/skill/GitHub/pool/gamification/plugin/Notion/Obsidian/local-corpus/RTK modules), 3 transports (stdio / SSE / Streamable HTTP), 33 scopes |
| A2A Server | `src/lib/a2a/` | JSON-RPC 2.0 agent protocol |

View File

@@ -4,7 +4,6 @@
### ✨ New Features
- **feat(dashboard):** adaptive context-budget dial on the compression settings panel — mode (`off` / `floor` / `replace-autotrigger`) and policy (`reserve-output` / `percentage` / `absolute`) persist via `PUT /api/settings/compression` `contextBudget`. Completes the dashboard half of #7005 (API + DB already shipped in #7183).
- **feat(sse): STRICT_ZERO_COST** — opt-in, off-by-default `freeAccessPolicy: "strict"` setting
that hard-verifies every auto-combo candidate against live quota state and per-connection
economic safety before it can be dispatched, going beyond `hidePaidModels`'s static catalog

View File

@@ -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 → 356 providers — 150+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot & Antigravity into FREE Claude / GPT / Gemini with auto-fallback. RTK + Caveman stacked compression saves 1595% tokens (~89% avg) — never hit limits. 356 AI providers · 150+ 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 → 355 providers — 150+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot & Antigravity into FREE Claude / GPT / Gemini with auto-fallback. RTK + Caveman stacked compression saves 1595% tokens (~89% avg) — never hit limits. 355 AI providers · 150+ free tiers · ~1.51B free tokens/mo · 19 routing strategies · $0 to start."/>
</div>
@@ -209,7 +209,7 @@ curl http://localhost:20128/v1/chat/completions \
</div>
<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint and 356 providers. Automatic fallback keeps routing while another healthy target is available. Six pillars: resilient fallback across 356 providers · up to 95% token savings on eligible workloads · $0 to start with 150+ free tiers and 53 recurring/keyless free-forever providers · 36 CLI/agent integrations through one config · OpenAI, Claude, Gemini and Responses API compatibility at /v1 · production controls including circuit breakers, TLS stealth, MCP 110 tools, A2A, memory, guardrails, evals and 39,000+ static test declarations across 5,100+ tracked test files."/>
<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint and 355 providers. Automatic fallback keeps routing while another healthy target is available. Six pillars: resilient fallback across 355 providers · up to 95% token savings on eligible workloads · $0 to start with 150+ free tiers and 53 recurring/keyless free-forever providers · 36 CLI/agent integrations through one config · OpenAI, Claude, Gemini and Responses API compatibility at /v1 · production controls including circuit breakers, TLS stealth, MCP 110 tools, A2A, memory, guardrails, evals and 39,000+ static test declarations across 5,100+ tracked test files."/>
<br/>
<br/>
@@ -462,7 +462,7 @@ All **19** strategies — mix & match per combo step:
</div>
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — a dated feature snapshot vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 356 providers, 150+ free tiers built in, 19 routing strategies, 12-engine token compression, built-in MCP server with 110 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA and 42 i18n UI locales. OmniRoute is MIT-licensed and self-hostable. Competitor capabilities and counts may change; see the linked methodology."/>
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — a dated feature snapshot vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 355 providers, 150+ free tiers built in, 19 routing strategies, 12-engine token compression, built-in MCP server with 110 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA and 42 i18n UI locales. OmniRoute is MIT-licensed and self-hostable. Competitor capabilities and counts may change; see the linked methodology."/>
<sub>📊 Full methodology &amp; per-feature detail vs 9router, OpenRouter, CLIProxyAPI &amp; LiteLLM → [`docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md`](docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md)</sub>
@@ -1244,7 +1244,7 @@ Métricas canônicas em 2026-08-24: **1.029 vídeos únicos** · **11.132.922 vi
<tr><td nowrap><b>Runtime</b></td><td>Node.js 22.x / 24.x LTS — <code>&gt;=22.22.2 &lt;23 || &gt;=24.0.0 &lt;27</code></td></tr>
<tr><td nowrap><b>Language</b></td><td>TypeScript 6.0 — <b>100% TypeScript</b> across <code>src/</code> and <code>open-sse/</code> (zero <code>any</code> in core since v2.0)</td></tr>
<tr><td nowrap><b>Framework</b></td><td>Next.js 16 + React 19 + Tailwind CSS 4</td></tr>
<tr><td nowrap><b>Database</b></td><td>better-sqlite3 (SQLite, WAL journaling) + LowDB (JSON legacy) — 122 domain modules, 169 migrations</td></tr>
<tr><td nowrap><b>Database</b></td><td>better-sqlite3 (SQLite, WAL journaling) + LowDB (JSON legacy) — 122 domain modules, 168 migrations</td></tr>
<tr><td nowrap><b>Memory</b></td><td>SQLite FTS5 full-text + int8-quantized vector embeddings, typed decay</td></tr>
<tr><td nowrap><b>Schemas</b></td><td>Zod 4 — MCP tool I/O validation + API contracts</td></tr>
<tr><td nowrap><b>Protocols</b></td><td>MCP (stdio / HTTP / SSE) + A2A v0.3 (JSON-RPC 2.0 + SSE)</td></tr>

View File

@@ -1 +0,0 @@
- **feat(providers):** add SeekAi (`seekai.cc`) as an OpenAI-compatible New-API gateway — catalog id `seekai` (alias `ska`), `https://seekai.cc/v1`, live `/v1/models` via `passthroughModels`, aggregator-list membership so New-API balance detection can opt in. No referral/aff codes. ([#11786](https://github.com/diegosouzapw/OmniRoute/issues/11786))

View File

@@ -1 +0,0 @@
- **feat(providers):** import-from-file modal shows per-row API errors and ships a downloadable CSV template ([#12071](https://github.com/diegosouzapw/OmniRoute/issues/12071))

View File

@@ -1 +0,0 @@
- **feat(providers):** dashboard search matches connection name and `baseUrl` so imported OpenAI-compat nodes surface on the provider card ([#12108](https://github.com/diegosouzapw/OmniRoute/issues/12108))

View File

@@ -1 +0,0 @@
- **feat(settings):** persist `headroomUrl` through Settings so status/start use the operator URL instead of only `HEADROOM_URL` ([#12306](https://github.com/diegosouzapw/OmniRoute/issues/12306))

View File

@@ -1 +0,0 @@
- **fix(grok-cli):** treat omitted SuperGrokPro `creditUsagePercent` as 0% used so Provider Limits still renders a weekly bar (proto3 zero-elision) ([#12312](https://github.com/diegosouzapw/OmniRoute/pull/12312)) — thanks @HouMinXi

View File

@@ -1 +0,0 @@
- **fix(quota):** drop the generic quota cache (agy / Antigravity / Claude OAuth) on an upstream 429 so reset-aware scoring does not keep a 60s stale snapshot, and force-refresh the next usage fetch so inner provider caches cannot recache the same window ([#12325](https://github.com/diegosouzapw/OmniRoute/pull/12325)) — thanks @HouMinXi

View File

@@ -1 +0,0 @@
- **chore(providers):** bump the Claude Code wire identity and the Devin bridge image pin from `2.1.220` to `2.1.258` ([#12402](https://github.com/diegosouzapw/OmniRoute/pull/12402)) — thanks @ggiak

View File

@@ -1 +0,0 @@
- **chore(quality):** rebaseline the file-size caps the hartmark batch grew past (`combos/page.tsx` via [#12355](https://github.com/diegosouzapw/OmniRoute/pull/12355), `open-sse/services/combo.ts` via [#12338](https://github.com/diegosouzapw/OmniRoute/pull/12338))

View File

@@ -1 +0,0 @@
- **chore(quality):** rebaseline the file-size caps the HouMinXi batch grew past when its PRs stacked (`providers/page.tsx`, `chatCore.ts`, `accountFallback.ts`) — each PR measured correctly in isolation, none saw the stacking

View File

@@ -1,7 +1,4 @@
{
"_rebaseline_2026_09_03_moonshot_native_quota": "PR feat/moonshot-native-quota own growth on release/v3.8.51: src/lib/db/migrationRunner.ts 1201->1206 (+5, case 172 retroactive guard for daily_quota_reset_* columns); src/sse/handlers/chat.ts 2434->2450 (+16, registerMoonshotQuotaFetcher + startup node scan at the existing quota-fetcher registration chokepoint); src/sse/services/auth.ts 3427->3450 (+23, resolveDailyResetForProvider + dailyReset arg on checkFallbackError); open-sse/services/accountFallback.ts 2422->2461 (+39, compatible-node credits_exhausted carve-out + TPD node-clock lock); tests/unit/account-fallback-service.test.ts 2008->2056 (+48, TPD/empty-wallet cases). Wiring at existing chokepoints; Moonshot host predicates, daily reset clock, and the balance fetcher live in new leaves under cap. Covered by tests/unit/moonshot-*.test.ts + account-fallback-service.test.ts (135/135 focused).",
"_rebaseline_2026_09_02_11786_seekai_provider": "PR #11786 (feat/11786-seekai-provider, closes #11786) own growth: src/shared/constants/providers/apikey/gateways.ts 1438->1458 (check-file-size split-newline=1459; the seekai APIKEY_PROVIDERS_GATEWAYS catalog entry plus authHint, additive data at the existing registry chokepoint, same god-file no-split rationale as prior gateways.ts rebaselines: #10987 logfare, #10531 freebuff). Covered by tests/unit/seekai-provider.test.ts.",
"_rebaseline_2026_09_02_12325_generic_429_invalidate": "PR #12325 own growth: open-sse/handlers/chatCore.ts 5946->5955 (+9 = the non-Codex 429 else-if that drops the generic quota wrapper and stamps force-refresh, plus a source-regex breadcrumb). Irreducible call-site wiring next to the existing Codex 429 invalidateCodexQuotaCache branch; not extractable without splitting handleChatCore mid-response. Covered by tests/unit/generic-quota-fetcher.test.ts (31/31) and tests/unit/antigravity-429-quota-cooldown.test.ts.",
"_rebaseline_2026_09_02_12429_wreq_migration_suite": "PR #12429 (wreq-js web-cookie transport): new test file tests/unit/tls-client-wreq-migration.test.ts at 1374 lines, above the 1200 new-file testCap. Frozen rather than split: it is the single cohesive regression suite for the transport migration (31 cases covering streaming, fragmented EOF sentinels, proxy isolation, first-byte and hard deadlines, binary responses and cancellation), and the cases share the native-transport harness the file sets up once. Splitting it during a merge would duplicate that harness across files for no coverage gain. Entered at the exact LOC, so it can only ratchet down from here.",
"_rebaseline_2026_09_02_12239_chatgpt_web_cleanroom": "PR #12239 (backryun, codex/restore-chatgpt-web-cleanroom) own growth at the two existing chat chokepoints for the clean-room ChatGPT Web transport: src/sse/handlers/chat.ts 2384->2424 (+40); open-sse/handlers/chatCore.ts 5946->5976 (+30). Additive dispatch wiring; the retirement guard is narrowed to the GPL-derived cgpt-web alias rather than removed, so #11754's provenance decision still holds for the old implementation. Same own-growth rationale as _rebaseline_2026_08_20_10531_freebuff_provider.",
"_rebaseline_2026_09_02_12412_grok_web_prettier": "PR #12412 (repository Prettier style applied to tests/unit/grok-web.test.ts): the reformat expands the file +277 lines (2436 -> 2713) with an identical parsed AST — no production code, no assertion changes. Cap set to 2985 rather than the exact 2713 on the operator's instruction (2026-09-02): ~10% headroom so routine additions to this suite do not re-trip the gate on formatting alone. Previous cap 2437. This is a deliberate exception to the down-only ratchet for one reformatted test file; every other entry keeps the #12411 tightening.",
@@ -207,7 +204,7 @@
"_rebaseline_basered_codebuddy_cn": "Base-red fix (#4664 CodeBuddy CN): oauth-providers-config.test.ts 867->870 (+3) to align the EXPECTED provider list/config with the codebuddy-cn provider that #4664 added to the registry without updating this test (it asserts 'exactly once').",
"_rebaseline_pr4613_compatible_provider_groups": "Reconcile #4613 already-merged growth: providers-page-utils.test.ts 1004->1052 (+48, buildCompatibleProviderGroups partition unit test). Fast-gate PR->release does not run check:file-size, so this surfaced post-merge.",
"tests/integration/chat-pipeline.test.ts": 1644,
"tests/unit/account-fallback-service.test.ts": 2056,
"tests/unit/account-fallback-service.test.ts": 2008,
"tests/unit/batch_api.test.ts": 1345,
"tests/unit/cc-compatible-provider.test.ts": 1225,
"tests/unit/chatcore-translation-paths.test.ts": 3447,
@@ -415,14 +412,14 @@
"open-sse/executors/codex.ts": 1499,
"open-sse/executors/cursor.ts": 1759,
"open-sse/executors/muse-spark-web.ts": 1405,
"open-sse/handlers/chatCore.ts": 5984,
"open-sse/handlers/chatCore.ts": 5976,
"open-sse/handlers/imageGeneration.ts": 3259,
"open-sse/handlers/search.ts": 1789,
"open-sse/mcp-server/schemas/tools.ts": 1621,
"open-sse/mcp-server/server.ts": 1572,
"open-sse/services/accountFallback.ts": 2467,
"open-sse/services/accountFallback.ts": 2422,
"open-sse/services/adobeFireflyBrowserLogin.ts": 1401,
"open-sse/services/combo.ts": 4036,
"open-sse/services/combo.ts": 4023,
"open-sse/translator/response/openai-responses.ts": 1466,
"open-sse/utils/cursorAgentProtobuf.ts": 1547,
"open-sse/utils/proxyFetch.ts": 1271,
@@ -431,15 +428,15 @@
"open-sse/vendor/codex-chatgpt-web/bridge.ts": 1322,
"src/app/(dashboard)/dashboard/HomePageClient.tsx": 1344,
"src/app/(dashboard)/dashboard/api-manager/ApiManagerPageClient.tsx": 3186,
"src/app/(dashboard)/dashboard/combos/page.tsx": 5018,
"src/app/(dashboard)/dashboard/combos/page.tsx": 5012,
"src/app/(dashboard)/dashboard/costs/CostOverviewTab.tsx": 1319,
"src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.tsx": 2491,
"src/app/(dashboard)/dashboard/providers/[id]/components/modals/EditConnectionModal.tsx": 1631,
"src/app/(dashboard)/dashboard/providers/page.tsx": 2025,
"src/app/(dashboard)/dashboard/providers/page.tsx": 2007,
"src/app/(dashboard)/dashboard/runtime/RuntimePageClient.tsx": 1201,
"src/app/(dashboard)/dashboard/settings/components/ProxyRegistryManager.tsx": 1475,
"src/app/(dashboard)/dashboard/settings/components/ResilienceTab.tsx": 1271,
"src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx": 1607,
"src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx": 1606,
"src/app/(dashboard)/dashboard/settings/components/SystemStorageTab.tsx": 1597,
"src/app/(dashboard)/dashboard/usage/components/EvalsTab.tsx": 2152,
"src/app/api/providers/[id]/models/route.ts": 2432,
@@ -448,14 +445,14 @@
"src/app/docs/lib/openapi.generated.ts": 1347,
"src/lib/db/apiKeys.ts": 1610,
"src/lib/db/core.ts": 1745,
"src/lib/db/migrationRunner.ts": 1206,
"src/lib/db/migrationRunner.ts": 1201,
"src/lib/tailscaleTunnel.ts": 1208,
"src/lib/tokenHealthCheck.ts": 1218,
"src/shared/components/RequestLoggerV2.tsx": 1718,
"src/shared/constants/providers/apikey/gateways.ts": 1459,
"src/shared/constants/providers/apikey/gateways.ts": 1439,
"src/shared/services/cliRuntime.ts": 1296,
"src/sse/handlers/chat.ts": 2450,
"src/sse/services/auth.ts": 3450,
"src/sse/handlers/chat.ts": 2424,
"src/sse/services/auth.ts": 3427,
"tests/unit/account-fallback-service.test.ts": 2453,
"tests/unit/provider-validation-specialty.test.ts": 4656
},
@@ -632,9 +629,5 @@
"_rebaseline_2026_06_30_v3842_release_chatgptweb_compression": "v3.8.42 cycle-close file-size reconciliation (DRIFT measured OK on each PR's base, stacked above frozen at the merge tip; fast-path PR->release/** does not run check:file-size). (1) open-sse/executors/chatgpt-web.ts 2870->3206 (+336 = #5531 portable SHA3-512 sentinel-PoW wiring with the native-vs-fallback digest path + #5536 GPT-5.5 Pro handoff branch; the pure Keccak-f[1600] fallback itself already lives in the separate leaf open-sse/utils/sha3-512.ts — the executor growth is the cohesive call-site/handoff logic, not extractable without hiding the sentinel chokepoint). (2) tests/unit/chatgpt-web.test.ts 2855->3159 (+304 = #5536 GPT-5.5 Pro handoff coverage; pair-file with its executor). (3) open-sse/services/compression/strategySelector.ts 997->1022 (+25 = #5527 T02 honest default-on pipeline inflation guard wiring at the existing finalizeStackedResult choke). All cohesive at existing chokepoints; covered by tests/unit/chatgpt-web-sha3-boringssl-5531.test.ts, chatgpt-web.test.ts (GPT-5.5 Pro), compression-pipeline-inflation-guard.test.ts.",
"open-sse/executors/chatgpt-web.ts": "3241",
"_rebaseline_2026_08_30_11771_vercel_gateway_passthrough": "PR #11771 adds passthroughModels: true (1 line) to the Vercel AI Gateway registry entry — no split available, single-line provider-config addition.",
"_relax_velocity_2026_08_30": "127 frozen line caps and cap/testCap raised by 20% (velocity phase; see quality-baseline.json _policy).",
"_rebaseline_2026_09_02_12325_merge_v3851": "Merge of release/v3.8.51 into #12325. Both sides grew chatCore.ts at the same chokepoint: #12239 took it 5946->5976 upstream, and this PR adds its +9 non-Codex 429 branch on top. check-file-size.mjs counts split(\"\\\\n\").length (trailing-newline empty element), so the merged file is 5981. The cap is the merged LOC, not either side alone; no other entry moves.",
"_rebaseline_2026_09_03_houminxi_batch_stacked": "Crescimento medido DEPOIS que os 9 PRs da leva HouMinXi entraram, quando cada um empilhou sobre o rebaseline do anterior: providers/page.tsx 2007->2025 (+18 = feedback de erro por linha do import CSV do #12504 somado a busca por nome/baseUrl do #12495, ambos no mesmo painel de conexoes); chatCore.ts 5981->5984 (+3 = o #12325 invalida o cache generico de quota no 429 upstream, ao lado do ramo Codex ja existente); accountFallback.ts 2461->2467 (+6 = o #12566 empilha a carve-out de familia Antigravity sobre o rebaseline 2422->2461 que o #12590 registrou para o carve-out credits_exhausted da Moonshot; os dois tocam checkFallbackError). Cada PR mediu certo isoladamente, mas nenhum enxergava o empilhamento. Fiacao em chokepoints existentes. NAO cobre codex.ts nem stream.ts, que ja violavam no tip antes desta leva (drift da base).",
"_rebaseline_2026_09_03_12604_claude_code_2_1_258": "PR #12604 (bump da wire identity do Claude Code 2.1.220->2.1.258, commits do @ggiak vindos do #12402) crescimento proprio: src/app/(dashboard)/dashboard/settings/components/RoutingTab.tsx 1606->1607 (+1, a linha do seletor que acompanha a nova versao de identidade). Uma linha num painel de settings ja existente; nao ha o que extrair. Coberto por client-identity-profiles e claude-codex-identity-version-sync (138/138 focados).",
"_rebaseline_2026_09_03_hartmark_batch": "Leva hartmark (#12293 #12355 #12447 #12445 #12446 #12460 #12461 #12338 #12448) crescimento proprio, medido no tip com os nove mergeados: src/app/(dashboard)/dashboard/combos/page.tsx 5012->5018 (+6, #12355 impede que a falha de bundling do tiktoken de um provider sem relacao derrube /api/providers, e o painel passa a lidar com o estado degradado); open-sse/services/combo.ts 4023->4036 (+13, #12338 nos fixes do universal-handoff: nota de bare-fallback, escopo por mesma requisicao e log da falha silenciosa). Fiacao em chokepoints existentes do roteamento de combo. NAO cobre codex.ts nem stream.ts, ja violando no tip antes desta leva (drift da base)."
"_relax_velocity_2026_08_30": "127 frozen line caps and cap/testCap raised by 20% (velocity phase; see quality-baseline.json _policy)."
}

View File

@@ -1,6 +1,6 @@
FROM node:26.0.0-bookworm-slim
ARG CLAUDE_CODE_VERSION=2.1.258
ARG CLAUDE_CODE_VERSION=2.1.220
ARG DEVIN_CLI_VERSION=3000.2.17
ARG TARGETARCH

View File

@@ -28,7 +28,7 @@ x-runtime: &runtime
context: ../..
dockerfile: docker/devin-bridge/Dockerfile
args:
CLAUDE_CODE_VERSION: 2.1.258
CLAUDE_CODE_VERSION: 2.1.220
DEVIN_CLI_VERSION: 3000.2.17
user: "10001:10001"
read_only: true

View File

@@ -4,22 +4,16 @@
Messages endpoint while the official Devin CLI supplies model responses over ACP stdio. It
does not modify the existing Anthropic, Claude OAuth, Claude Web, or `devin-cli` providers.
> **Current status: pinned Claude Code `2.1.258`; offline and live validation last recorded
> on `2.1.220`.** The `2.1.220` pin completed three isolated scenarios through Devin CLI
> `3000.2.17` and model `swe-1-7-lightning`; that final live run proved client-owned `Read`,
> `Edit`, and `Bash` turns, successful `npm test` results, project command and skill
> discovery, Devin-only routing, and zero Claude egress. The pin was then raised to `2.1.258`
> (the CLI generation OmniRoute's Claude identity impersonates, and the first line that ships
> the Fable 5.1 tier natively). On the new pin the install layer and `claude --version` were
> verified on the pinned base image, and the bridge unit suite, `compose config` and the
> static isolation proof pass — but the offline mock scenario and the live three-scenario
> suite have not been re-run yet. Re-run them (see "Updating pinned tools") before relying on
> the bridge with this pin.
> **Current status: offline and live validated.** The pinned Claude Code `2.1.220` completed
> three isolated scenarios through Devin CLI `3000.2.17` and model
> `swe-1-7-lightning`. The final live run proved client-owned `Read`, `Edit`, and `Bash`
> turns, successful `npm test` results, project command and skill discovery, Devin-only
> routing, and zero Claude egress.
## Architecture
```text
Claude Code 2.1.258 (isolated non-root Linux container)
Claude Code 2.1.220 (isolated non-root Linux container)
-> http://omniroute:20128/v1/messages
-> devin-cli-agentic (Claude-format, no-auth provider)
-> devin acp --agent-type summarizer (official ACP stdio, no Devin tools)

View File

@@ -90,17 +90,17 @@ Runs on every PR to `main`. Blocks merge on failure.
Runs after `test-coverage`. Blocks merge on failure.
| Script | Validates | Blocking |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| `quality:collect` | Emits `quality-metrics.json` (ESLint warning count, coverage from merged shard report) | Yes (upstream of ratchet) |
| `quality:ratchet` | Each metric in `quality-baseline.json` has not regressed (ESLint warnings ≤ baseline; coverage ≥ baseline) | Yes |
| `check:duplication` | Code duplication (jscpd@4) does not exceed baseline in `quality-baseline.json` | Yes |
| `check:complexity` | File-level cyclomatic complexity does not exceed the cap (core ESLint `complexity` + `max-lines-per-function`) | Yes |
| `check:cognitive-complexity` | Cognitive complexity ratchet (`eslint-plugin-sonarjs`) — separate ESLint pass; CI runs both merged as the single `check:complexity-ratchets` step | Yes |
| `check:dead-code` | Unused exports / files ratchet (knip) does not regress vs baseline | Yes |
| `check:compression-budget` | Compression benchmark budget — per-engine token-savings floors must not regress | Yes |
| `check:type-coverage` | Percent-typed ratchet (`type-coverage`) does not regress; largely subsumes `typecheck:noimplicit:core` | Yes |
| `check:codeql-ratchet` | Open CodeQL alert count does not regress (reads via `gh api`; graceful-skip without token) | Yes |
| Script | Validates | Blocking |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| `quality:collect` | Emits `quality-metrics.json` (ESLint warning count, coverage from merged shard report) | Yes (upstream of ratchet) |
| `quality:ratchet` | Each metric in `quality-baseline.json` has not regressed (ESLint warnings ≤ baseline; coverage ≥ baseline) | Yes |
| `check:duplication` | Code duplication (jscpd@4) does not exceed baseline in `quality-baseline.json` | Yes |
| `check:complexity` | File-level cyclomatic complexity does not exceed the cap (core ESLint `complexity` + `max-lines-per-function`) | Yes |
| `check:cognitive-complexity` | Cognitive complexity ratchet (`eslint-plugin-sonarjs`) — separate ESLint pass; CI runs both merged as the single `check:complexity-ratchets` step | Yes |
| `check:dead-code` | Unused exports / files ratchet (knip) does not regress vs baseline | Yes |
| `check:compression-budget` | Compression benchmark budget — per-engine token-savings floors must not regress | Yes |
| `check:type-coverage` | Percent-typed ratchet (`type-coverage`) does not regress; largely subsumes `typecheck:noimplicit:core` | Yes |
| `check:codeql-ratchet` | Open CodeQL alert count does not regress (reads via `gh api`; graceful-skip without token) — refresh cadence and manual trigger: see "CodeQL ratchet" below | Yes |
### Job: `quality-extended`
@@ -324,6 +324,36 @@ Commit this file alongside the change that improved the metric. A PR that improv
metric without updating the baseline will be caught by `--require-tighten` (Fase 6A.5,
pending implementation).
### CodeQL ratchet: refresh cadence and manual trigger
`check:codeql-ratchet` reads **repo state, refreshed on a schedule — not per PR.**
`gh api repos/diegosouzapw/OmniRoute/code-scanning/default-setup` reports
`state: configured`, `schedule: weekly`: GitHub's default-setup scan, not a per-push
analysis. Consequence: after a PR that FIXES alerts merges, the ratchet keeps reading
the old, higher count until the next scheduled scan runs — so it reports a regression
on every open PR, including the fixing PR's own follow-ups, until the scan catches up.
**Manual refresh**: `gh workflow run codeql.yml --ref release/vX.Y.Z` re-runs the
analysis and republishes alerts within minutes. Read `.github/workflows/codeql.yml`
first — its header explains it is `workflow_dispatch`-only **because it conflicts with
GitHub's "default setup"** (`CodeQL analyses from advanced configurations cannot be
processed when the default setup is enabled`). Restoring `push`/`pull_request`/
`schedule` triggers requires an **owner action first**: Settings → Code security →
CodeQL: Default → Advanced. Do not add a `schedule:` trigger without that switch — it
will only produce failing runs.
**Tighten the baseline after the count drops**`node scripts/check/check-codeql-ratchet.mjs
--update` writes the new measured count into `quality-baseline.json`
`metrics.codeqlAlerts.value`, so the ratchet does not silently permit a regression back
up to the old ceiling. Worked example (2026-09-02/03): PR #12502 fixed 7 real alerts
(13 → 6 measured open); PR #12530 tightened the frozen baseline 11 → 6 to match; the
remaining 6 were then dismissed with per-alert justification down to 0 open.
**Dismissals are the operator's call (Hard Rule #14)** — never dismiss a CodeQL alert
without recording the technical justification in the dismissal comment: `won't fix` for
an upstream-protocol requirement, `used in tests` for a test fixture, `false positive`
for a sanitizer CodeQL cannot see (precedent: `docs/security/ERROR_SANITIZATION.md`).
---
## Test Retry Policy (WS5.4, v3.8.49)

View File

@@ -309,7 +309,7 @@ Every compressed request includes stats in the server logs:
| Phase 2 | Standard, Aggressive, Ultra | ✅ Shipped |
| Phase 3 | RTK, Stacked, Compression Combos | ✅ Shipped |
| Phase 4 | Output Styles, SLM-tier Ultra, eval harness | ✅ Shipped |
| Phase 4C | Adaptive context-budget ("dial") — compute engine + API (`contextBudget` on `PUT /api/settings/compression`) + dashboard mode/policy controls | ✅ Shipped |
| Phase 4C | Adaptive context-budget ("dial") — compute engine + API (`contextBudget` on `PUT /api/settings/compression`) | ✅ Shipped (API-configurable; dashboard controls not yet built, #7005) |
---

View File

@@ -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 (356 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 86 top-level commands: 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 (355 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 86 top-level commands: 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.348;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

View File

@@ -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: 356 providers, 150+ free providers built-in, 19 routing strategies, 12-engine token compression, a built-in MCP server with 110 tools, A2A protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, desktop/Termux/PWA, 42 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: 355 providers, 150+ free providers built-in, 19 routing strategies, 12-engine token compression, a built-in MCP server with 110 tools, A2A protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, desktop/Termux/PWA, 42 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

View File

@@ -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 and 356 providers. Six pillars. Resilient fallback: automatic routing continues while another healthy target is available. Save up to 95 percent of eligible tokens: RTK plus Caveman stacked compression averages about 89 percent on tool-heavy sessions. Zero dollars to start: 150+ providers with a free tier and 53 recurring or keyless free-forever providers. Every tool works: 36 CLI and agent integration records, including Claude Code, Codex, Cursor, Cline, Copilot and Antigravity, through one config. One endpoint: OpenAI, Claude, Gemini and Responses API translation at /v1. Production controls: circuit breakers, TLS stealth, MCP with 110 tools, A2A, memory, guardrails, evals, and 39,000+ static test declarations across 5,100+ tracked test files.">
<svg viewBox="0 0 1200 540" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The OmniRoute promise: one endpoint and 355 providers. Six pillars. Resilient fallback: automatic routing continues while another healthy target is available. Save up to 95 percent of eligible tokens: RTK plus Caveman stacked compression averages about 89 percent on tool-heavy sessions. Zero dollars to start: 150+ providers with a free tier and 53 recurring or keyless free-forever providers. Every tool works: 36 CLI and agent integration records, including Claude Code, Codex, Cursor, Cline, Copilot and Antigravity, through one config. One endpoint: OpenAI, Claude, Gemini and Responses API translation at /v1. Production controls: circuit breakers, TLS stealth, MCP with 110 tools, A2A, memory, guardrails, evals, and 39,000+ static test declarations across 5,100+ tracked test files.">
<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">356 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">355 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 356 providers in</text>
<text x="66" y="204" font-size="13.5" fill="#a1a1aa">Auto-fallback across 355 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 while a healthy target remains.</text>
</g>

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -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 356 providers — 150+ 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: 356 AI providers, 150+ 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 355 providers — 150+ 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: 355 AI providers, 150+ 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">356 providers</tspan><tspan fill="#7ee787" font-weight="800">150+ 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">355 providers</tspan><tspan fill="#7ee787" font-weight="800">150+ 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&#160;&#160;&#160;&#160;<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

View File

@@ -122,8 +122,6 @@ Access via: WhatsApp, Telegram, Slack, Discord, iMessage, Signal...
## 📖 Provider Setup
To bulk-add API-key connections from a CSV or JSON file, use **Dashboard → Providers → Import from file**. Columns are positional (`provider,name,apiKey,baseUrl,priority`); `provider` must already exist as a managed provider or a compatible node. See [Import providers from a CSV or JSON file](../providers/CSV-IMPORT.md).
### 🔐 Subscription Providers
#### Claude Code (Pro/Max)

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -18,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -128,7 +128,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -393,7 +393,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -437,7 +437,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -130,7 +130,7 @@ request (see `open-sse/services/claudeCodeCompatible.ts`):
| Header | Value |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `Authorization` | `Bearer <api-key>` |
| `User-Agent` | `claude-cli/2.1.258 (external, sdk-cli)` |
| `User-Agent` | `claude-cli/2.1.219 (external, sdk-cli)` |
| `anthropic-version` | `2023-06-01` |
| `anthropic-beta` | `claude-code-20250219,interleaved-thinking-2025-05-14,effort-2025-11-24` |
| Per-connection redact-thinking beta toggle | Adds `redact-thinking-2026-02-12` for upstreams that specifically require redacted thinking streams |

View File

@@ -1,43 +0,0 @@
---
title: "Import providers from a CSV or JSON file"
---
# Import providers from a CSV or JSON file
Dashboard → Providers → **Import from file** creates API-key connections from a CSV or JSON list. Each row can target a different provider. Partial failure is the contract: valid rows still import when others fail, and the modal lists why the failed rows were rejected.
This import does **not** create new OpenAI/Anthropic-compatible endpoint nodes. Create those first (Dashboard → Providers → Add OpenAI-Compatible, or `omniroute nodes add`), then import rows whose `provider` column is that node's id. A per-row `baseUrl` can still override the node's URL.
## CSV (positional)
Column names are cosmetic. The parser splits each row and destructures by index:
| Index | Field | Required | Notes |
| ----- | ----- | -------- | ----- |
| 0 | `provider` | yes | Existing managed provider id (`openai`, `anthropic`, …) **or** an already-registered OpenAI/Anthropic-compatible **node** id |
| 1 | `name` | yes | Connection display name |
| 2 | `apiKey` | yes | API key |
| 3 | `baseUrl` | no | Per-row URL override |
| 4 | `priority` | no | Integer 1100 |
A first line whose first column is the literal word `provider` (any case) is skipped as a header. Blank lines and `#` comments are skipped.
Download a starter file from the import modal (**Download CSV template**). Example:
```csv
# OmniRoute provider import (positional columns)
provider,name,apiKey,baseUrl,priority
openai,Prod OpenAI,sk-your-openai-key,,1
```
A made-up id such as `openai-compatible-chat-001` is not a node. The API returns `Unknown or unsupported provider` for that row; the modal shows it next to the row name.
## JSON
A JSON array of objects with the same fields (`provider`, `name`, `apiKey`, `baseUrl?`, `priority?`). Unlike CSV, JSON keys are named.
```json
[
{ "provider": "openai", "name": "Prod OpenAI", "apiKey": "sk-your-openai-key", "priority": 1 }
]
```

View File

@@ -8,7 +8,6 @@
"AGENTROUTER",
"ZED-DOCKER",
"CURSOR-DOCKER",
"CURSOR-API-KEY-AND-CLI",
"CSV-IMPORT"
"CURSOR-API-KEY-AND-CLI"
]
}

View File

@@ -622,7 +622,7 @@ process.env[`${PROVIDER_ID}_USER_AGENT`]
| Variable | Default Value | When to Update |
| -------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `CLAUDE_USER_AGENT` | `claude-cli/2.1.258 (external, cli)` | When Anthropic releases a new CLI version |
| `CLAUDE_USER_AGENT` | `claude-cli/2.1.219 (external, cli)` | When Anthropic releases a new CLI version |
| `CLAUDE_DISABLE_TOOL_NAME_CLOAK` | `false` | `executors/base.ts` + `executors/cliproxyapi.ts` | Set to `1`/`true` to forward third-party harness tool names verbatim to Anthropic on both Anthropic-bound paths (native OAuth and CLIProxyAPI). By default the executor deterministically aliases non-Claude-Code tool names (Claude Code canonical mapping where one exists, otherwise PascalCase) and reverses them on the response via `_toolNameMap`, so harnesses with snake_case tools are not refused as fingerprinted third-party clients. Debugging only. |
| `CODEX_USER_AGENT` | `codex-cli/0.142.0 (Windows 10.0.26200; x64)` | When OpenAI updates the Codex CLI |
| `CODEX_CLIENT_VERSION` | `0.131.0` | Override Codex client version independently of full UA string |

View File

@@ -1,16 +1,16 @@
---
title: "Provider Reference"
version: 3.8.51
lastUpdated: 2026-09-03
lastUpdated: 2026-09-02
---
# 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-09-03
> **Last generated:** 2026-09-02
Total providers: **356**. See category breakdown below.
Total providers: **355**. See category breakdown below.
## Categories
@@ -118,7 +118,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
| `zai-web` | `zw` | Z.ai Web | Web cookie | [link](https://chat.z.ai) | Copy the "token" value from chat.z.ai → DevTools → Application → Local Storage. Do not copy cookies; OmniRoute handles the per-request CAPTCHA through its browser transport. | — |
| `zenmux-free` | `zmf` | ZenMux Free (Web) | Web cookie | [link](https://zenmux.ai) | Login at zenmux.ai, then export all cookies using EditThisCookie or Cookie-Editor and paste the full Cookie header string here. Refresh every ~30 days. | — |
## API Key Providers (paid / paid-with-free-credits) (238)
## API Key Providers (paid / paid-with-free-credits) (237)
| ID | Alias | Name | Tags | Website | Notes |
|----|-------|------|------|---------|-------|
@@ -310,7 +310,6 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
| `sarvam` | `sarvam` | Sarvam AI | API key | [link](https://docs.sarvam.ai) | ₹1,000 in free signup credits — never expire |
| `scaleway` | `scw` | Scaleway AI | API key | [link](https://www.scaleway.com/en/docs/ai-data/generative-apis/) | 1M free tokens for new accounts — EU/GDPR compliant (Paris), Qwen3 235B & Llama 70B |
| `sealion` | `sealion` | SEA-LION | API key | [link](https://sea-lion.ai) | Sign in at sea-lion.ai with Google (no card, no region wall), create an API key, then paste it here. |
| `seekai` | `ska` | SeekAi | API key, aggregator | [link](https://seekai.cc) | Create an API key at https://seekai.cc, then paste it here as a Bearer token. |
| `segmind` | `segmind` | Segmind | API key, image, video | [link](https://segmind.com) | Use your Segmind API key in the x-api-key header. OmniRoute targets https://api.segmind.com/v1/<model> and returns the generated image/video bytes directly. |
| `sensenova` | `sensenova` | SenseNova | API key | [link](https://platform.sensenova.cn) | Get API key at platform.sensenova.cn |
| `siliconflow` | `siliconflow` | SiliconFlow | API key | [link](https://cloud.siliconflow.com) | $1 free credits plus currently listed $0 models after identity verification; availability and limits may change |

View File

@@ -117,8 +117,8 @@ Applied to: `system` blocks, all `messages[].content`, and `tools[].description`
For third-party Anthropic relays that only accept "real Claude Code" traffic:
- `CLAUDE_CODE_COMPATIBLE_USER_AGENT = "claude-cli/2.1.258 (external, sdk-cli)"`
- `CLAUDE_CODE_COMPATIBLE_STAINLESS_PACKAGE_VERSION = "0.112.1"`
- `CLAUDE_CODE_COMPATIBLE_USER_AGENT = "claude-cli/2.1.220 (external, sdk-cli)"`
- `CLAUDE_CODE_COMPATIBLE_STAINLESS_PACKAGE_VERSION = "0.94.0"`
- `CLAUDE_CODE_COMPATIBLE_STAINLESS_RUNTIME_VERSION = "v26.3.0"`
- `anthropic-beta = "claude-code-20250219,interleaved-thinking-2025-05-14,effort-2025-11-24"` by default
- The per-connection "Enable redact-thinking beta" toggle adds `redact-thinking-2026-02-12` when a CC Compatible upstream specifically requires redacted thinking streams
@@ -241,7 +241,7 @@ All MITM endpoints require management auth (`requireCliToolsAuth`). The sudo pas
| Variable | Default |
| ------------------------ | --------------------------------------------------------------- |
| `CLAUDE_USER_AGENT` | `claude-cli/2.1.258 (external, cli)` |
| `CLAUDE_USER_AGENT` | `claude-cli/2.1.220 (external, cli)` |
| `CODEX_USER_AGENT` | `codex-cli/0.149.0 (Windows 10.0.26200; x64)` |
| `GITHUB_USER_AGENT` | `GitHubCopilotChat/0.54.0` |
| `ANTIGRAVITY_USER_AGENT` | `antigravity/2.0.1 linux/arm64 google-api-nodejs-client/10.3.0` |

12
llm.txt
View File

@@ -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 356 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 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 355 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -14,7 +14,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
- **Runtime:** Node.js `>=22.22.2 <23 || >=24.0.0 <27`, ES Modules (`"type": "module"`)
- **Framework:** Next.js 16 (App Router) with TypeScript 6
- **Database:** SQLite via better-sqlite3 (local, zero-config, 169 migrations)
- **Database:** SQLite via better-sqlite3 (local, zero-config, 168 migrations)
- **State management:** Zustand (client), SQLite (server persistence)
- **UI:** React 19, Tailwind CSS 4, Recharts for analytics, @lobehub/icons for 130+ provider SVG icons
- **Auth:** OAuth 2.0 (PKCE) for providers, bcrypt for local user auth
@@ -124,7 +124,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
│ │ │ ├── secrets.ts # Secrets management
│ │ │ ├── stateReset.ts # State reset utilities
│ │ │ ├── migrationRunner.ts # Schema migration runner
│ │ │ └── migrations/ # 169 versioned SQL migration files
│ │ │ └── migrations/ # 168 versioned SQL migration files
│ │ ├── evals/ # Eval runner and scheduler
│ │ ├── memory/ # Persistent conversational memory
│ │ │ ├── extraction.ts # Memory extraction from conversations
@@ -277,7 +277,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **356 AI providers** with automatic format translation
- **355 AI providers** with automatic format translation
- **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible)
- **19 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, cache-optimized, context-relay, fusion, pipeline
- **4-tier fallback**: Subscription → API Key → Cheap → Free
@@ -389,7 +389,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
8. **ProviderIcon component:** Unified icon system using `@lobehub/icons` (130+ SVG) with PNG fallback and generic icon fallback chain. Used on providers, dashboard, and agents pages.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 169 SQL migrations.
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 122 `src/lib/db/` modules with 168 SQL migrations.
10. **Upstream headers:** Custom headers merged in executors after default auth; same header name replaces executor value. Forbidden header names in `src/shared/constants/upstreamHeaders.ts`.
@@ -433,7 +433,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
4. **Environment variables:** All configuration is in `.env` (from `.env.example`). Key vars: `PORT`, `NEXT_PUBLIC_BASE_URL`, `API_KEY`, `ADMIN_PASSWORD`.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 169 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
5. **Database layer:** Operations go through `src/lib/db/` modules (122 domain-specific files, 168 migrations). `localDb.ts` is re-exports only — add new functions to the proper `db/*.ts` module.
6. **Tests** use Node.js built-in test runner + Vitest. Run `npm test`. Vitest for MCP/autoCombo (`npm run test:vitest`). Playwright for E2E (`npm run test:e2e`). Coverage gate: ratchet vs `quality-baseline.json`, absolute floor 60% statements/lines/functions/branches.

View File

@@ -270,7 +270,6 @@ import { voidAiProvider } from "./registry/void-ai/index.ts";
import { helixmindProvider } from "./registry/helixmind/index.ts";
import { tabitokenProvider } from "./registry/tabitoken/index.ts";
import { logfareProvider } from "./registry/logfare/index.ts";
import { seekaiProvider } from "./registry/seekai/index.ts";
export const REGISTRY: Record<string, RegistryEntry> = {
aimlapi: aimlapiProvider,
@@ -545,5 +544,4 @@ export const REGISTRY: Record<string, RegistryEntry> = {
helixmind: helixmindProvider,
tabitoken: tabitokenProvider,
logfare: logfareProvider,
seekai: seekaiProvider,
};

View File

@@ -1,18 +0,0 @@
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
/**
* SeekAi (https://seekai.cc) — QuantumNous New-API gateway.
* Live-verified 2026-09-02: GET /api/status → system_name=SeekAi,
* version=v1.0.0-rc.25, quota_display_type=USD. GET /v1/models is
* API-key gated (401 Invalid token without a key). Catalog is dynamic;
* no static seed. Referral/aff query params stay out of this entry
* (no-hardcoded-referral-codes).
*/
export const seekaiProvider = buildOpenAiCompatibleRegistryEntry({
id: "seekai",
alias: "ska",
baseUrl: "https://seekai.cc/v1/chat/completions",
modelsUrl: "https://seekai.cc/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -26,7 +26,6 @@ import {
} from "../services/antigravityCredits.ts";
import { persistCreditBalance, getAllPersistedCreditBalances } from "@/lib/db/creditBalance";
import { setConnectionRateLimitUntil } from "@/lib/db/providers";
import { markAntigravityModelQuotaExhausted } from "../services/antigravityFamilyCooldown.ts";
import { getMitmAlias } from "@/lib/db/models";
import {
MAX_ANTIGRAVITY_OUTPUT_TOKENS,
@@ -246,15 +245,17 @@ export function createCreditsExtractionTransform(
);
}
export function markConnectionQuotaExhausted(
connectionId: string,
retryAfterMs: number,
model?: string | null
): void {
/**
* Persist a quota-exhausted cooldown to the DB for `connectionId` so that
* cross-request and post-restart routing skips this connection until the
* cooldown expires. Exported for unit testing. @internal
*/
export function markConnectionQuotaExhausted(connectionId: string, retryAfterMs: number): void {
try {
if (markAntigravityModelQuotaExhausted(connectionId, retryAfterMs, model)) return;
setConnectionRateLimitUntil(connectionId, Date.now() + retryAfterMs);
} catch {}
} catch {
// DB write failure must never crash the request path
}
}
/**
@@ -1619,7 +1620,7 @@ export class AntigravityExecutor extends BaseExecutor {
updateAntigravityRemainingCredits
);
if (creditsResult) return { kind: "return", result: creditsResult };
if (retryMs) markConnectionQuotaExhausted(accountId, retryMs, ctx.model);
if (retryMs) markConnectionQuotaExhausted(accountId, retryMs);
}
return {

View File

@@ -384,7 +384,6 @@ import { sanitizeOpenAITool } from "../services/toolSchemaSanitizer.ts";
import { isCompactResponsesEndpoint } from "../executors/codex.ts";
import { persistCodexChildQuotaResponse } from "../services/codexAccount/index.ts";
import { invalidateCodexQuotaCache } from "../services/codexQuotaFetcher.ts";
import { invalidateGenericQuotaCacheOnStatus } from "../services/genericQuotaFetcher.ts";
import { translateNonStreamingResponse } from "./responseTranslator.ts";
import { extractToolSchemaMap } from "../translator/response/openai-responses/toolSchemas.ts";
import { unwrapClineNonStreamingEnvelope } from "./chatCore/clineResponseEnvelope.ts";
@@ -3240,14 +3239,6 @@ export async function handleChatCore({
const errMessage = err instanceof Error ? err.message : String(err);
log?.debug?.("CODEX", `Failed to persist codex quota state: ${errMessage}`);
}
} else if (attemptConnectionId && res.response.status === 429) {
// Dropped generic quota cache after 429
invalidateGenericQuotaCacheOnStatus({
provider,
connectionId: String(attemptConnectionId),
status: res.response.status,
isolateProbe: await shouldIsolateProbeFailures(),
});
}
// Track Gemini RPM + RPD request counts for 429 classification

View File

@@ -13,7 +13,6 @@
import { extractProviderWarnings } from "@/lib/compliance/providerAudit";
import { logAuditEvent } from "@/lib/compliance";
import { emit } from "@/lib/events/eventBus";
import { maybeLogToolCallSpecViolation } from "./toolCallSpecViolationAudit.ts";
import type { RequestCompletedPayload, RequestFailedPayload } from "@/lib/events/types";
import { saveCallLog } from "@/lib/usageDb";
import type { VideoBridgeLogRedactionEntry } from "@/lib/guardrails/videoBridge";
@@ -393,15 +392,6 @@ export function persistAttemptLogs(args: PersistAttemptLogsArgs, ctx: PersistAtt
});
}
maybeLogToolCallSpecViolation({
responseBody,
provider,
model,
connectionId: finalConnectionId,
httpStatus: status,
requestId: skillRequestId,
});
const capturedPipeline = reqLogger?.getPipelinePayloads?.() ?? null;
const pipelinePayloads = detailedLoggingEnabled
? (capturedPipeline ?? {})

View File

@@ -1,46 +0,0 @@
/**
* Post-request on-spec audit for duplicated tool_calls.
*
* Extracted from persistAttemptLogs so attemptLogging.ts stays at the frozen
* complexity count. validateResponseQuality's streaming peek only sees the
* START of a stream, so a duplicate that arrives after real content has
* already been relayed cannot fail the attempt over — this is the first
* point the fully assembled body is available. Too late to retry; a durable
* audit row still beats a clean HTTP 200 with no trace.
*
* Observed: minimax-m3:free via OpenRouter/GMICloud, 2026-09-02, duplicated
* a heartbeat_respond call byte-for-byte.
*/
import { logAuditEvent } from "@/lib/compliance";
import { findToolCallSpecViolation } from "../../services/combo/validateQuality.ts";
export function maybeLogToolCallSpecViolation(input: {
responseBody: unknown;
provider: string | null | undefined;
model: string | null | undefined;
connectionId: string | null;
httpStatus: number;
requestId: string;
}): void {
const violation = findToolCallSpecViolation(input.responseBody);
if (!violation) return;
logAuditEvent({
action: "provider.spec_violation",
actor: "system",
target:
[input.provider, input.connectionId].filter(Boolean).join(":") ||
input.provider ||
input.model,
resourceType: "provider_spec_violation",
status: "warning",
requestId: input.requestId,
details: {
provider: input.provider,
model: input.model,
connectionId: input.connectionId,
httpStatus: input.httpStatus,
violation,
},
});
}

View File

@@ -49,8 +49,7 @@ import {
} from "../../src/shared/constants/providers";
import { resolveUseUpstream429BreakerHints } from "../../src/shared/utils/providerHints";
import { getCodexModelScope } from "../config/codexQuotaScopes.ts";
import { getQuotaScopedModelForProvider, isAntigravityQuotaProvider } from "./antigravityQuotaFamily.ts";
import { persistAntigravityFamilyCooldownIfQuota } from "./antigravityFamilyCooldown.ts";
import { getQuotaScopedModelForProvider } from "./antigravityQuotaFamily.ts";
import {
classifyGeminiQuotaMetricFromText,
isRpdExhausted,
@@ -64,8 +63,6 @@ import {
parseDelayString,
MAX_SHORT_RETRY_HINT_MS,
} from "./retryAfterJson.ts";
import { isMoonshotAccountBalanceExhausted } from "./usage/moonshotOpenPlatform.ts";
import { isTpdRateLimit, resolveTpdCooldownMs } from "./dailyQuotaReset.ts";
// Pre-compiled regex constants for hot-path retry parsing (avoid per-call compilation)
const RETRY_AFTER_RE = /retry\s+after\s+(\d+)\s*s/i;
@@ -653,9 +650,6 @@ export async function recordCoreOwnedAntigravityQuotaState({
exactCooldownIsUpstreamReset: retryHintBypassesMaxCooldownMs(fallback.retryHintSource),
}
);
if (lockout.cooldownMs > 0 && isProviderExhaustedReason(fallback)) {
persistAntigravityFamilyCooldownIfQuota({ provider, connectionId, model, cooldownMs: lockout.cooldownMs, reason: "quota_exhausted" });
}
return { cooldownMs: lockout.cooldownMs, failureCount: lockout.failureCount };
}
@@ -1607,8 +1601,7 @@ export function isDailyQuotaExhausted(errorText: string): boolean {
return (
lower.includes("today's quota") ||
lower.includes("daily quota") ||
lower.includes("try again tomorrow") ||
lower.includes("tpd rate limit")
lower.includes("try again tomorrow")
);
}
@@ -1654,12 +1647,7 @@ export function checkFallbackError(
headers: Headers | Record<string, string> | null = null,
profileOverride: ProviderProfile | null = null,
structuredError?: { code?: string | null; type?: string | null } | null,
rotation?: { account?: unknown } | null,
dailyReset?: {
timezone?: unknown;
hour?: unknown;
nowMs?: number;
} | null,
rotation?: { account?: unknown } | null
): {
shouldFallback: boolean;
cooldownMs: number;
@@ -1942,13 +1930,8 @@ export function checkFallbackError(
}
}
// T10 (sub2api #1169) + #8247: credits/quota exhausted; *-compatible-* nicknames stay model-scoped
// unless the body is an account-level Open Platform empty wallet.
if (
shouldUseQuotaSignal &&
isCreditsExhausted(errorStr) &&
(!isCompatibleProvider(provider) || isMoonshotAccountBalanceExhausted(errorStr))
) {
// T10 (sub2api #1169) + #8247: credits/quota exhausted; *-compatible-* nicknames stay model-scoped.
if (shouldUseQuotaSignal && isCreditsExhausted(errorStr) && !isCompatibleProvider(provider)) {
return {
shouldFallback: true,
cooldownMs: COOLDOWN_MS.paymentRequired ?? 3600 * 1000, // 1h cooldown
@@ -1957,43 +1940,17 @@ export function checkFallbackError(
};
}
// Daily quota exhausted. TPD uses the node clock / header; other daily
// quota text still uses getMsUntilTomorrow. TPD without either is not a
// host-midnight lock — fall through to short 429.
// Daily quota exhausted — lock model until tomorrow
if (shouldUseQuotaSignal && isDailyQuotaExhausted(errorStr)) {
if (isTpdRateLimit(errorStr)) {
const headerResetAtMs = parseResetFromHeaders(headers);
const tpdMs = resolveTpdCooldownMs(errorStr, {
timezone: dailyReset?.timezone,
hour: dailyReset?.hour,
nowMs: dailyReset?.nowMs,
headerResetAtMs,
});
if (tpdMs == null) {
// no clock, no header — short 429, do not guess midnight
console.warn(
"[accountFallback] TPD 429 without node daily-reset clock or Reset header; using short cooldown",
{ provider },
);
} else {
return {
shouldFallback: true,
cooldownMs: tpdMs,
reason: RateLimitReason.QUOTA_EXHAUSTED,
dailyQuotaExhausted: true,
};
}
} else {
const msUntilTomorrow = getMsUntilTomorrow();
// Cap at 24 hours to handle timezone edge cases
const cooldownMs = Math.min(msUntilTomorrow, 24 * 60 * 60 * 1000);
return {
shouldFallback: true,
cooldownMs,
reason: RateLimitReason.QUOTA_EXHAUSTED,
dailyQuotaExhausted: true,
};
}
const msUntilTomorrow = getMsUntilTomorrow();
// Cap at 24 hours to handle timezone edge cases
const cooldownMs = Math.min(msUntilTomorrow, 24 * 60 * 60 * 1000);
return {
shouldFallback: true,
cooldownMs,
reason: RateLimitReason.QUOTA_EXHAUSTED,
dailyQuotaExhausted: true,
};
}
// Issue #2321 (5h subscription quota) + Issue #3709 (ollama-cloud weekly
@@ -2432,7 +2389,12 @@ export function applyErrorState<T extends AccountState | null | undefined>(
// (`markConnectionQuotaExhausted`) so a DB failure can never crash the
// chat path. See issue #1 (per-account 429 cascade not persisting).
const connId = (account as AccountState | null | undefined)?.id;
if (typeof connId === "string" && connId.length > 0 && effectiveCooldownMs > 0 && nextState.rateLimitedUntil && !isAntigravityQuotaProvider(prov)) {
if (
typeof connId === "string" &&
connId.length > 0 &&
effectiveCooldownMs > 0 &&
nextState.rateLimitedUntil
) {
try {
const untilMs = cooldownUntilMs(nextState.rateLimitedUntil);
if (Number.isFinite(untilMs) && untilMs > Date.now()) {

View File

@@ -1,158 +0,0 @@
/**
* Persist Antigravity/agy quota cooldowns per model family (gemini vs claude)
* on the connection row, without cooling the whole account.
*/
import { lockModel } from "./accountFallback.ts";
import {
getAntigravityQuotaFamily,
isAntigravityQuotaProvider,
} from "./antigravityQuotaFamily.ts";
type JsonRecord = Record<string, unknown>;
const FAMILY_PSD_KEY = "antigravityFamilyRateLimitedUntil";
function asRecord(value: unknown): JsonRecord {
return value && typeof value === "object" && !Array.isArray(value)
? (value as JsonRecord)
: {};
}
function parseUntilMs(value: unknown): number {
if (typeof value === "number" && Number.isFinite(value)) return value;
if (typeof value === "string" && value.trim()) {
const ms = /^\d+(\.\d+)?$/.test(value.trim()) ? Number(value) : Date.parse(value);
return Number.isFinite(ms) ? ms : NaN;
}
return NaN;
}
function dummyModelForFamily(family: "gemini" | "claude"): string {
return family === "gemini" ? "gemini-family-lock" : "claude-family-lock";
}
function lockAntigravityFamilyModel(
connectionId: string,
model: string,
reason: string,
cooldownMs: number
): void {
lockModel("agy", connectionId, model, reason, cooldownMs);
lockModel("antigravity", connectionId, model, reason, cooldownMs);
}
export async function persistAntigravityFamilyCooldown(params: {
connectionId: string;
model: string;
rateLimitedUntil: string;
}): Promise<JsonRecord | null> {
if (!params.model.trim()) return null;
const family = getAntigravityQuotaFamily(params.model);
if (family === "other") return null;
const { getProviderConnectionById, updateProviderConnection } = await import(
"@/lib/db/providers"
);
const conn = (await getProviderConnectionById(params.connectionId)) as
| { provider?: string; providerSpecificData?: JsonRecord | null }
| null;
if (!conn || !isAntigravityQuotaProvider(conn.provider ?? null)) return null;
const psd = asRecord(conn.providerSpecificData);
const untils = asRecord(psd[FAMILY_PSD_KEY]);
const existingMs = parseUntilMs(untils[family]);
const nextMs = parseUntilMs(params.rateLimitedUntil);
if (!Number.isFinite(nextMs)) return psd;
if (Number.isFinite(existingMs) && existingMs > Date.now() && existingMs >= nextMs) {
return psd;
}
const nextPsd: JsonRecord = {
...psd,
[FAMILY_PSD_KEY]: { ...untils, [family]: params.rateLimitedUntil },
};
await updateProviderConnection(params.connectionId, { providerSpecificData: nextPsd });
return nextPsd;
}
/** Fire-and-forget family PSD write. RPM/burst 429s must pass reason !== quota_exhausted. */
export function persistAntigravityFamilyCooldownIfQuota(params: {
provider?: string | null;
connectionId: string;
model?: string | null;
cooldownMs: number;
reason?: string | null;
}): void {
if (!isAntigravityQuotaProvider(params.provider)) return;
if (!params.model?.trim() || params.cooldownMs <= 0) return;
if (params.reason != null && params.reason !== "quota_exhausted") return;
void persistAntigravityFamilyCooldown({
connectionId: params.connectionId,
model: params.model,
rateLimitedUntil: new Date(Date.now() + params.cooldownMs).toISOString(),
}).catch(() => {});
}
export async function persistAntigravityPreflightFamilyLock(params: {
provider: string;
connectionId: string;
model: string;
unavailableUntil: string;
}): Promise<void> {
const cooldownMs = Math.max(0, Date.parse(params.unavailableUntil) - Date.now());
lockAntigravityFamilyModel(params.connectionId, params.model, "quota_exhausted", cooldownMs);
await persistAntigravityFamilyCooldown({
connectionId: params.connectionId,
model: params.model,
rateLimitedUntil: params.unavailableUntil,
});
}
export function rehydrateAntigravityFamilyLocks(
provider: string,
connectionId: string,
providerSpecificData: JsonRecord | null | undefined
): void {
if (!isAntigravityQuotaProvider(provider)) return;
const untils = asRecord(asRecord(providerSpecificData)[FAMILY_PSD_KEY]);
const now = Date.now();
for (const family of ["gemini", "claude"] as const) {
const untilMs = parseUntilMs(untils[family]);
if (!Number.isFinite(untilMs) || untilMs <= now) continue;
const model = dummyModelForFamily(family);
const remainingMs = untilMs - now;
lockAntigravityFamilyModel(connectionId, model, "quota_exhausted", remainingMs);
}
}
export function rehydrateAntigravityFamilyLocksForConnections(
provider: string,
connections: Array<{ id: string; providerSpecificData?: unknown }>
): void {
if (!isAntigravityQuotaProvider(provider)) return;
for (const conn of connections) {
rehydrateAntigravityFamilyLocks(
provider,
conn.id,
conn.providerSpecificData as JsonRecord | null | undefined
);
}
}
/** Family lock for executor quota exhaustion. Returns false when model is absent. */
export function markAntigravityModelQuotaExhausted(
connectionId: string,
retryAfterMs: number,
model?: string | null
): boolean {
if (!model) return false;
lockAntigravityFamilyModel(connectionId, model, "quota_exhausted", retryAfterMs);
persistAntigravityFamilyCooldownIfQuota({
provider: "agy",
connectionId,
model,
cooldownMs: retryAfterMs,
reason: "quota_exhausted",
});
return true;
}

View File

@@ -54,77 +54,3 @@ export function getQuotaScopeLabelForProvider(
if (provider !== "antigravity" && provider !== "agy") return "model";
return getAntigravityQuotaFamily(model) === "other" ? "model" : "family";
}
export function isAntigravityQuotaProvider(provider: string | null | undefined): boolean {
return provider === "antigravity" || provider === "agy";
}
export function quotaWindowNamesForScope(
names: string[],
scope?: { provider?: string | null; requestedModel?: string | null }
): string[] {
if (!scope?.requestedModel || !isAntigravityQuotaProvider(scope.provider)) return names;
const scoped = selectAntigravityQuotaWindowNames(names, scope.requestedModel);
return scoped.length > 0 ? scoped : names;
}
/** Min remaining % across scoped windows, or 100 when an Antigravity family scope matched none. */
export function remainingPercentFromQuotaWindows(
rawWindows: Record<string, unknown>,
scope?: { provider?: string | null; requestedModel?: string | null }
): number | null {
const names = Object.keys(rawWindows);
const namesToScan = quotaWindowNamesForScope(names, scope);
let minRemaining: number | null = null;
for (const name of namesToScan) {
const windowInfo = rawWindows[name];
if (!windowInfo || typeof windowInfo !== "object") continue;
const percentUsed = Number((windowInfo as Record<string, unknown>).percentUsed);
if (!Number.isFinite(percentUsed)) continue;
const remaining = Math.max(0, Math.min(100, (1 - percentUsed) * 100));
minRemaining = minRemaining === null ? remaining : Math.min(minRemaining, remaining);
}
if (minRemaining !== null) return minRemaining;
if (scope?.requestedModel && namesToScan !== names) return 100;
return null;
}
/**
* Windows that belong to the requested Antigravity family. Claude weekly must
* not ride along on a Gemini request (and the reverse).
*/
export function selectAntigravityQuotaWindowNames(
quotaNames: string[],
requestedModel: string | null | undefined
): string[] {
if (!requestedModel) return quotaNames;
const requestedFamily = getAntigravityQuotaFamily(requestedModel);
const cleanRequestedModel = requestedModel.replace(/^(antigravity|agy)\//, "");
const bareModel = cleanRequestedModel.includes("/")
? cleanRequestedModel.slice(cleanRequestedModel.lastIndexOf("/") + 1)
: cleanRequestedModel;
if (requestedFamily === "other") {
return quotaNames.filter((windowName) => {
const bare = windowName.replace(/^(antigravity|agy)\//, "");
return bare === bareModel || bare === cleanRequestedModel;
});
}
const familyAggregates =
requestedFamily === "gemini"
? ["gemini_weekly"]
: requestedFamily === "claude"
? ["claude_gpt_weekly"]
: [];
const exactWindows = quotaNames.filter((windowName) => {
const bare = windowName.replace(/^(antigravity|agy)\//, "");
return bare === bareModel;
});
const aggregateWindows = familyAggregates.filter((key) => quotaNames.includes(key));
const scoped = [...exactWindows, ...aggregateWindows];
if (scoped.length > 0) return scoped;
return quotaNames.filter((windowName) => getAntigravityQuotaFamily(windowName) === requestedFamily);
}

View File

@@ -613,13 +613,12 @@ export async function buildAutoCandidates(
const quota = await quotaPromises.get(quotaKey)!;
resetWindowAffinity = calculateResetWindowAffinity(quota, resetWindowConfig);
if (!quotaCutoffBlocked) {
quotaRemaining = quotaRemainingPercentFromQuota(quota, { provider, requestedModel: modelStr });
quotaRemaining = quotaRemainingPercentFromQuota(quota);
}
if (!quotaCutoffBlocked && quotaCutoffEnabled) {
const cutoffDecision = evaluateQuotaCutoff(
quota as QuotaInfo | null,
buildAutoQuotaThresholds(provider, connection, resilienceSettings),
{ provider, requestedModel: modelStr }
buildAutoQuotaThresholds(provider, connection, resilienceSettings)
);
if (!cutoffDecision.proceed) {
quotaCutoffBlocked = true;
@@ -1380,7 +1379,7 @@ async function handleComboChatInner({
resilienceSettings,
quotaCutoffResetWindowConfig,
combo.name,
log, modelStr
log
);
if (quotaCutoff.blocked) {
log.info(
@@ -1661,16 +1660,8 @@ async function handleComboChatInner({
}
}
// Universal handoff: inject existing handoff if model changed. i === 0
// only: a fallback target (i > 0) serves the SAME client request the
// failed primary target would have served, with the original messages
// already intact -- there's nothing to hand off, since the client never
// saw the earlier target fail. Injecting a handoff note there replaces
// real context with a context-free note, which weaker fallback models
// have been observed treating as license to fabricate content instead
// of just answering the actual request (#12227 follow-up).
// Universal handoff: inject existing handoff if model changed
if (
i === 0 &&
universalHandoffConfig.enabled &&
relayOptions?.sessionId &&
!(body as Record<string, unknown>)?.[SKIP_UNIVERSAL_HANDOFF_FLAG]
@@ -1936,14 +1927,7 @@ async function handleComboChatInner({
provider,
target.connectionId ?? undefined
);
// i === 0 only: a same-request fallback target (i > 0) never
// needs a summary generated for it -- see the injection-site
// comment above. recordSessionModelUsage above stays
// unconditional regardless of i: it must reflect whichever
// model actually served THIS response, since the next
// request's i === 0 comparison depends on that being
// accurate even when this response came from a fallback.
if (i === 0 && prevModel && prevModel !== modelStr) {
if (prevModel && prevModel !== modelStr) {
const handoffSourceMessages =
Array.isArray(body?.messages) && body.messages.length > 0
? body.messages
@@ -4031,5 +4015,8 @@ async function handleRoundRobinCombo({
}
log.warn("COMBO-RR", `All models failed | ${msg}`);
return new Response(JSON.stringify({ error: { message: msg } }), { status, headers: { "Content-Type": "application/json" } });
return new Response(JSON.stringify({ error: { message: msg } }), {
status,
headers: { "Content-Type": "application/json" },
});
}

View File

@@ -7,7 +7,6 @@
*/
import { EXECUTOR_CONTRACT_VIOLATION_CODE } from "../../config/constants.ts";
import { remainingPercentFromQuotaWindows } from "../antigravityQuotaFamily.ts";
import { errorResponse } from "../../utils/error.ts";
import { parseModel } from "../model.ts";
import { isSelfInflictedUpstreamTimeout } from "../../handlers/chatCore/cooldownClassification.ts";
@@ -432,24 +431,24 @@ export function clampPercent(value: number): number {
return Math.max(0, Math.min(100, value));
}
export function quotaRemainingPercentFromQuota(
quota: unknown,
scope?: { provider?: string | null; requestedModel?: string | null }
): number {
export function quotaRemainingPercentFromQuota(quota: unknown): number {
if (!quota || typeof quota !== "object") return 100;
const record = quota as Record<string, unknown>;
if (record.limitReached === true) return 0;
const windows = record.windows;
if (windows && typeof windows === "object" && !Array.isArray(windows)) {
const fromWindows = remainingPercentFromQuotaWindows(
windows as Record<string, unknown>,
scope
);
if (fromWindows !== null) return fromWindows;
let minRemaining: number | null = null;
for (const windowInfo of Object.values(windows as Record<string, unknown>)) {
if (!windowInfo || typeof windowInfo !== "object") continue;
const percentUsed = Number((windowInfo as Record<string, unknown>).percentUsed);
if (!Number.isFinite(percentUsed)) continue;
const remaining = clampPercent((1 - percentUsed) * 100);
minRemaining = minRemaining === null ? remaining : Math.min(minRemaining, remaining);
}
if (minRemaining !== null) return minRemaining;
}
if (record.limitReached === true) return 0;
const percentUsed = Number(record.percentUsed);
if (Number.isFinite(percentUsed)) return clampPercent((1 - percentUsed) * 100);
return 100;

View File

@@ -245,8 +245,7 @@ export async function isPinnedTargetModelScopedUnusable(args: {
resilienceSettings,
quotaCutoffResetWindowConfig,
comboName,
log ?? { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} },
target.modelStr
log ?? { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} }
);
if (cutoff.blocked) return true;
}

View File

@@ -97,8 +97,7 @@ export async function resolveQuotaExhaustionCutoffForTarget(
resilienceSettings: ResilienceSettings | null | undefined,
resetWindowConfig: ResetWindowConfig,
comboName: string,
log: { debug?: (...args: unknown[]) => void; warn?: (...args: unknown[]) => void },
requestedModel?: string | null
log: { debug?: (...args: unknown[]) => void; warn?: (...args: unknown[]) => void }
): Promise<{ blocked: boolean; reason?: string }> {
const quotaCutoffEnabled =
(resilienceSettings ?? resolveResilienceSettings(null))?.quotaPreflight?.enabled === true;
@@ -127,8 +126,7 @@ export async function resolveQuotaExhaustionCutoffForTarget(
});
const cutoffDecision = evaluateQuotaCutoff(
quota as QuotaInfo | null,
buildAutoQuotaThresholds(provider, connection, resilienceSettings),
{ provider, requestedModel: requestedModel ?? null }
buildAutoQuotaThresholds(provider, connection, resilienceSettings)
);
if (!cutoffDecision.proceed) {
return { blocked: true, reason: cutoffDecision.reason || "quota_exhausted" };

View File

@@ -16,45 +16,6 @@ import { evaluateResponseValidation, type ResponseValidationConfig } from "./res
import { getReasoningTokens } from "../../../src/lib/usage/tokenAccounting.ts";
import type { ComboRetryAfter } from "./types.ts";
/**
* Detects tool_calls entries within one assistant message that repeat the
* exact same function name + arguments verbatim -- always a bug (no
* legitimate use calls one tool twice with identical arguments in the same
* turn), and a real observed failure mode of at least one free-tier
* streaming model (minimax-m3:free via OpenRouter/GMICloud, 2026-09-02:
* duplicated a heartbeat_respond call byte-for-byte, confirmed at the raw
* SSE wire level -- an upstream bug, not an OmniRoute reconstruction
* artifact). Used two ways: to fail a non-streaming response over to a
* sibling combo target (see validateResponseQuality below), and, post-
* stream, to flag an already-relayed streaming response as an on-spec
* violation despite its clean HTTP 200 (see attemptLogging.ts's
* persistAttemptLogs) -- a streaming response can't be retried once real
* content has started reaching the client (the quality-gate peek below only
* ever validates the START of a stream, by design, to avoid buffering the
* whole response and defeating streaming's latency purpose), so flagging it
* after the fact is what's actually achievable for that path.
*/
export function findToolCallSpecViolation(responseBody: unknown): string | null {
const json = isRecord(responseBody) ? responseBody : null;
const choices = json?.choices;
const firstChoice = Array.isArray(choices) ? choices[0] : null;
const message = isRecord(firstChoice) ? firstChoice.message : null;
const toolCalls = isRecord(message) ? message.tool_calls : null;
if (!Array.isArray(toolCalls) || toolCalls.length < 2) return null;
const seen = new Set<string>();
for (const call of toolCalls) {
const fn = isRecord(call) ? call.function : null;
if (!isRecord(fn) || typeof fn.name !== "string" || typeof fn.arguments !== "string") {
continue;
}
const signature = `${fn.name}\u0000${fn.arguments}`;
if (seen.has(signature)) return `duplicate tool_calls entry for "${fn.name}"`;
seen.add(signature);
}
return null;
}
export function toRetryAfterDisplayValue(value: ComboRetryAfter): string | Date {
if (typeof value !== "number") return value;
if (value > 0 && value < 1_000_000_000) {
@@ -366,9 +327,9 @@ export async function validateResponseQuality(
function isTerminalUsageOnlyChunk(parsed: Record<string, unknown>, eventType: string): boolean {
return Boolean(
parsed.usage &&
typeof parsed.usage === "object" &&
!Array.isArray(parsed.choices) &&
!eventType.startsWith("response.")
typeof parsed.usage === "object" &&
!Array.isArray(parsed.choices) &&
!eventType.startsWith("response.")
);
}
@@ -773,11 +734,6 @@ export async function validateResponseQuality(
}
const hasToolCalls = Array.isArray(toolCalls) && toolCalls.length > 0;
const specViolation = findToolCallSpecViolation(json);
if (specViolation) {
return { valid: false, reason: specViolation };
}
if (!hasContent && !hasToolCalls) {
return { valid: false, reason: "empty content and no tool_calls in response" };
}

View File

@@ -407,10 +407,7 @@ async function generateHandoffAsync(options: {
relayConfig.relayMode
);
const historyText = formatMessagesForPrompt(selectedMessages);
if (!historyText) {
logUniversalHandoffOutcome("unavailable", options.comboName, "empty selected-message history");
return;
}
if (!historyText) return;
const summaryPrompt = HANDOFF_PROMPT_TEMPLATE.replace("{HISTORY}", historyText);
const summaryBody = {
@@ -424,14 +421,7 @@ async function generateHandoffAsync(options: {
};
const response = await options.handleSingleModel(summaryBody, summaryModel);
if (!response.ok) {
logUniversalHandoffOutcome(
"unavailable",
options.comboName,
`summary model call failed: status=${response.status} model=${summaryModel}`
);
return;
}
if (!response.ok) return;
let content = "";
try {
@@ -446,14 +436,7 @@ async function generateHandoffAsync(options: {
}
const parsed = parseHandoffJSON(content);
if (!parsed) {
logUniversalHandoffOutcome(
"unparseable",
options.comboName,
`model=${summaryModel} contentPreview=${JSON.stringify(content.slice(0, 200))}`
);
return;
}
if (!parsed) return;
upsertHandoff({
sessionId: options.sessionId,
@@ -589,7 +572,7 @@ export function buildUniversalHandoffSystemMessage(
<transfer_reason>${escapedReason}</transfer_reason>
<previous_model>${escapedPrev}</previous_model>
<current_model>${escapedCurr}</current_model>
<note>No prior-session summary is available for this handoff. The input below (e.g. a tool result) is the entire context you have -- do not assume or invent details about a broader conversation you cannot see.</note>
<note>A continuación se resume toda la conversacion para continuar sin perder el hilo.</note>
</context_handoff>`;
}
@@ -704,23 +687,6 @@ export function resetUniversalHandoffCooldowns(): void {
universalHandoffCooldowns.clear();
}
// Every non-"generated" outcome across both handoff generators (this one and
// the older generateHandoffAsync above) used to be silent -- context_handoffs
// staying empty gave no signal on WHY (upstream call failing vs. malformed
// output vs. no history to summarize). Every live handoff then falls back to
// the bare no-summary note (buildUniversalHandoffSystemMessage's `!payload`
// branch / the context-relay equivalent), which is what actually reaches the
// model/user; without this log that always reads as a mystery instead of a
// traceable cause.
function logUniversalHandoffOutcome(
outcome: "unavailable" | "unparseable",
comboName: string,
detail: string
): void {
if (process.env.NODE_ENV === "test") return;
console.warn(`[universal-handoff] ${outcome} (combo=${comboName}): ${detail}`);
}
/**
* Generate a universal handoff summary for any model/provider switch.
*/
@@ -743,10 +709,7 @@ async function generateUniversalHandoffAsync(options: {
options.relayMode
);
const historyText = formatMessagesForPrompt(selectedMessages);
if (!historyText) {
logUniversalHandoffOutcome("unavailable", options.comboName, "empty selected-message history");
return "unavailable";
}
if (!historyText) return "unavailable";
const summaryPrompt = HANDOFF_PROMPT_TEMPLATE.replace("{HISTORY}", historyText);
const summaryModel = options.handoffModel || options.currModel;
@@ -772,25 +735,22 @@ async function generateUniversalHandoffAsync(options: {
};
const response = await options.handleSingleModel(summaryBody, summaryModel);
if (!response.ok) {
const detail = `summary model call failed: status=${response.status} model=${summaryModel}`;
logUniversalHandoffOutcome("unavailable", options.comboName, detail);
return "unavailable";
}
if (!response.ok) return "unavailable";
let content = "";
try {
content = getResponseText((await response.clone().json()) as Record<string, unknown>);
const json = (await response.clone().json()) as Record<string, unknown>;
content = getResponseText(json);
} catch {
content = await response.clone().text().catch(() => "");
try {
content = await response.clone().text();
} catch {
content = "";
}
}
const parsed = parseHandoffJSON(content);
if (!parsed) {
const preview = JSON.stringify(content.slice(0, 200));
logUniversalHandoffOutcome("unparseable", options.comboName, `model=${summaryModel} contentPreview=${preview}`);
return "unparseable";
}
if (!parsed) return "unparseable";
upsertHandoff({
sessionId: options.sessionId,

View File

@@ -23,90 +23,6 @@ export type TurnDisplayContent = {
toolName: string | null;
};
type CanonicalTurnLike = {
role: "system" | "user" | "assistant" | "tool";
text: string;
blockKind: "text" | "tool_use" | "tool_result";
toolName: string | null;
};
type JsonRecord = Record<string, unknown>;
function asRecord(value: unknown): JsonRecord | null {
return value && typeof value === "object" ? (value as JsonRecord) : null;
}
function turnsFromBody(body: unknown): CanonicalTurnLike[] {
const rec = asRecord(body);
return rec ? extractCanonicalTurns(rec) : [];
}
/**
* extractCanonicalTurns's Chat Completions branch only reads a message's
* `content` -- a tool-calling assistant message carries its call in
* `tool_calls` instead with `content: null`, so it silently produces no turn
* at all and the matching conversation_turn_nodes row can never resolve.
* Deliberately scoped to this read-only display path instead of extending
* extractCanonicalTurns itself: that function also drives
* conversationTracker.ts's write-path identity/hashing, and this codebase's
* only caller of it there (chat.ts's resolveConversationId) always feeds the
* client-facing Responses-API body -- never Chat Completions
* `messages`/`tool_calls` -- so extending it there would be unreachable for
* real traffic here but still carries real write-path identity-hash risk for
* any other caller/format that function might ever serve. Mirrors
* extractCanonicalTurns's own Responses-shape function_call handling: one
* turn per call, role "tool" (matches how a Responses API function_call item,
* which also carries no `role`, canonicalizes -- not "assistant"), toolName
* from the call, text the raw arguments string untouched (already a JSON
* string in both APIs, so passing it through unmodified is what a
* byte-identical hash against the original Responses-shaped item needs).
*/
function extractChatCompletionsToolUseTurns(messages: unknown): CanonicalTurnLike[] {
if (!Array.isArray(messages)) return [];
const turns: CanonicalTurnLike[] = [];
for (const item of messages) {
const rec = asRecord(item) ?? {};
if (rec.role !== "assistant" || !Array.isArray(rec.tool_calls)) continue;
for (const call of rec.tool_calls) {
const fn = asRecord(asRecord(call)?.function);
const args = fn?.arguments;
if (typeof args !== "string" || !args) continue;
turns.push({
role: "tool",
text: args,
blockKind: "tool_use",
toolName: typeof fn?.name === "string" ? fn.name : null,
});
}
}
return turns;
}
function turnsFromClientResponse(clientResponse: unknown): CanonicalTurnLike[] {
const rec = asRecord(clientResponse);
if (!rec) return [];
const summary = asRecord(rec.summary);
const output = Array.isArray(rec.output) ? rec.output : summary?.output;
return Array.isArray(output) ? extractCanonicalTurns({ input: output }) : [];
}
function turnsFromProviderRequest(body: unknown): CanonicalTurnLike[] {
const rec = asRecord(body);
return [...turnsFromBody(rec), ...extractChatCompletionsToolUseTurns(rec?.messages)];
}
function indexTurns(result: Map<string, TurnDisplayContent>, turns: CanonicalTurnLike[]): void {
for (const turn of turns) {
const hash = hashTurnContent(turn);
if (result.has(hash)) continue;
result.set(hash, {
textPreview: turn.text,
blockKind: turn.blockKind,
toolName: turn.toolName,
});
}
}
/**
* Resolve display content for a batch of turn nodes, keyed by content_hash.
* Content_hash is sha256(role+text) only — real traffic has plenty of
@@ -148,10 +64,19 @@ export function resolveTurnDisplayContent(
for (const relPath of artifactPathByCorrelationId.values()) {
const { artifact, state } = readCallArtifact(relPath);
if (state !== "ready") continue;
const pipeline = asRecord(artifact?.pipeline);
indexTurns(result, turnsFromBody(asRecord(pipeline?.clientRawRequest)?.body));
indexTurns(result, turnsFromClientResponse(pipeline?.clientResponse));
indexTurns(result, turnsFromProviderRequest(asRecord(pipeline?.providerRequest)?.body));
const clientRawRequest = artifact?.pipeline?.clientRawRequest as { body?: unknown } | undefined;
const body = clientRawRequest?.body;
if (!body || typeof body !== "object") continue;
for (const turn of extractCanonicalTurns(body as Record<string, unknown>)) {
const hash = hashTurnContent(turn);
if (result.has(hash)) continue;
result.set(hash, {
textPreview: turn.text,
blockKind: turn.blockKind,
toolName: turn.toolName,
});
}
}
return result;
}

View File

@@ -1,145 +0,0 @@
/**
* Node-level daily quota reset clock.
*
* TPD cooldown endpoint: operator-configured IANA timezone + local hour.
* No default timezone. Do not call getMsUntilTomorrow() from here.
*/
export function isValidIanaTimeZone(tz: string): boolean {
if (typeof tz !== "string" || tz.trim() === "") return false;
try {
new Intl.DateTimeFormat("en-US", { timeZone: tz.trim() }).format();
return true;
} catch {
return false;
}
}
export function isValidResetHour(hour: unknown): hour is number {
return typeof hour === "number" && Number.isInteger(hour) && hour >= 0 && hour <= 23;
}
export function nodeDailyResetConfigured(timezone: unknown, hour: unknown): boolean {
return typeof timezone === "string" && isValidIanaTimeZone(timezone) && isValidResetHour(hour);
}
type ZonedParts = {
year: number;
month: number;
day: number;
hour: number;
minute: number;
second: number;
};
function zonedParts(ms: number, timeZone: string): ZonedParts {
const fmt = new Intl.DateTimeFormat("en-US", {
timeZone,
hourCycle: "h23",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
const bag: Record<string, string> = {};
for (const part of fmt.formatToParts(new Date(ms))) {
if (part.type !== "literal") bag[part.type] = part.value;
}
return {
year: Number(bag.year),
month: Number(bag.month),
day: Number(bag.day),
hour: Number(bag.hour),
minute: Number(bag.minute),
second: Number(bag.second),
};
}
function addCalendarDay(year: number, month: number, day: number): {
year: number;
month: number;
day: number;
} {
const utc = Date.UTC(year, month - 1, day + 1);
const dt = new Date(utc);
return { year: dt.getUTCFullYear(), month: dt.getUTCMonth() + 1, day: dt.getUTCDate() };
}
/** Convert wall-clock time in `timeZone` to epoch ms. */
function zonedLocalToUtc(
year: number,
month: number,
day: number,
hour: number,
minute: number,
second: number,
timeZone: string,
): number {
const wanted = Date.UTC(year, month - 1, day, hour, minute, second);
let guess = wanted;
for (let i = 0; i < 4; i++) {
const p = zonedParts(guess, timeZone);
const asIfUtc = Date.UTC(p.year, p.month - 1, p.day, p.hour, p.minute, p.second);
const delta = asIfUtc - wanted;
if (delta === 0) return guess;
guess -= delta;
}
return guess;
}
/**
* Next local `hour:00:00` in `timezone` strictly after `nowMs`.
* If now lands exactly on that instant, return the following cycle.
*/
export function nextDailyResetAtMs(timezone: string, hour: number, nowMs: number): number {
const now = zonedParts(nowMs, timezone);
let date = { year: now.year, month: now.month, day: now.day };
let next = zonedLocalToUtc(date.year, date.month, date.day, hour, 0, 0, timezone);
if (next <= nowMs) {
date = addCalendarDay(date.year, date.month, date.day);
next = zonedLocalToUtc(date.year, date.month, date.day, hour, 0, 0, timezone);
}
return next;
}
export function parseTpdLimitFromText(text: string): number | null {
const m = /limit:\s*(\d+)/i.exec(text);
if (!m) return null;
const n = Number(m[1]);
return Number.isFinite(n) ? n : null;
}
export function isTpdRateLimit(errorText: string | null | undefined): boolean {
return String(errorText || "")
.toLowerCase()
.includes("tpd rate limit");
}
export type TpdCooldownOptions = {
timezone?: unknown;
hour?: unknown;
nowMs?: number;
headerResetAtMs?: number | null;
};
/**
* Cooldown for a TPD 429. Header reset wins; else the node clock.
* Both missing → null (caller uses short 429, does not guess midnight).
*/
export function resolveTpdCooldownMs(
errorText: string | null | undefined,
options: TpdCooldownOptions = {},
): number | null {
if (!isTpdRateLimit(errorText)) return null;
const now = options.nowMs ?? Date.now();
if (typeof options.headerResetAtMs === "number" && options.headerResetAtMs > now) {
return options.headerResetAtMs - now;
}
if (typeof options.timezone === "string" && isValidResetHour(options.hour)) {
if (!nodeDailyResetConfigured(options.timezone, options.hour)) return null;
return nextDailyResetAtMs(options.timezone, options.hour, now) - now;
}
return null;
}

View File

@@ -25,53 +25,10 @@ import {
type QuotaInfo,
} from "./quotaPreflight.ts";
type UsageFetcher = (
connection: Parameters<typeof getUsageForProvider>[0],
options?: { forceRefresh?: boolean }
) => Promise<unknown>;
let usageFetcherOverride: UsageFetcher | null = null;
// 60s — matches Codex's TTL. Long enough to avoid hammering upstream usage
// endpoints on every routing decision, short enough that a near-exhausted
// account is skipped within one minute of crossing its threshold.
const CACHE_TTL_MS = 60_000;
/** Drop unused force-refresh flags once inner provider caches (60s5min) have expired. */
const PENDING_FORCE_REFRESH_TTL_MS = CACHE_TTL_MS * 5;
/** key → Date.now() when invalidate asked the next fetch to force-refresh. */
const pendingForceRefresh = new Map<string, number>();
/** key → last convert-null / throw while force-refresh was pending. */
const pendingForceRefreshMiss = new Map<string, number>();
/** Test-only: inject the usage dispatcher; pass null to restore. */
export function __setGenericUsageFetcherForTests(fetcher: UsageFetcher | null): void {
usageFetcherOverride = fetcher;
}
/** Test-only: backdate a pending force-refresh so TTL expiry is unit-testable. */
export function __agePendingForceRefreshForTests(
provider: string,
connectionId: string,
ageMs: number
): void {
pendingForceRefresh.set(cacheKey(provider, connectionId), Date.now() - ageMs);
}
/** Test-only: backdate a convert-null miss so the 60s hammer-guard is unit-testable. */
export function __agePendingForceRefreshMissForTests(
provider: string,
connectionId: string,
ageMs: number
): void {
pendingForceRefreshMiss.set(cacheKey(provider, connectionId), Date.now() - ageMs);
}
/** Test-only: drop all wrapper/flag maps so tests cannot leak across ids. */
export function __resetGenericQuotaFetcherForTests(): void {
cache.clear();
pendingForceRefresh.clear();
pendingForceRefreshMiss.clear();
}
interface CacheEntry {
quota: QuotaInfo;
@@ -81,72 +38,15 @@ interface CacheEntry {
const cache = new Map<string, CacheEntry>();
function cacheKey(provider: string, connectionId: string): string {
return `${provider.trim()}::${connectionId.trim()}`;
return `${provider}::${connectionId}`;
}
function dropExpiredPendingForceRefresh(key: string, now: number): boolean {
const stampedAt = pendingForceRefresh.get(key);
if (stampedAt === undefined) return true;
if (now - stampedAt > PENDING_FORCE_REFRESH_TTL_MS) {
pendingForceRefresh.delete(key);
pendingForceRefreshMiss.delete(key);
return true;
}
return false;
}
// Lazy expiry on read — same as the provider breaker. Name stays `is*` because
// callers only need a boolean; the map is not a public API.
function isPendingForceRefresh(key: string, now: number = Date.now()): boolean {
if (dropExpiredPendingForceRefresh(key, now)) return false;
return pendingForceRefresh.has(key);
}
function markPendingForceRefreshMiss(key: string): void {
if (isPendingForceRefresh(key)) pendingForceRefreshMiss.set(key, Date.now());
}
function cachedQuotaIfFresh(
key: string,
forceRefresh: boolean,
now: number
): QuotaInfo | null {
if (forceRefresh) return null;
const cached = cache.get(key);
if (cached && now - cached.fetchedAt < CACHE_TTL_MS) return cached.quota;
return null;
}
function isForceRefreshMissCooling(
key: string,
forceRefresh: boolean,
now: number
): boolean {
if (!forceRefresh) return false;
const missedAt = pendingForceRefreshMiss.get(key);
return missedAt !== undefined && now - missedAt < CACHE_TTL_MS;
}
/** True when a concurrent 429 re-stamped a still-live flag during fetchUsage. */
function isConcurrentForceRefresh(key: string, refreshStamp: number | undefined): boolean {
const currentStamp = pendingForceRefresh.get(key);
if (currentStamp === refreshStamp) return false;
return (
currentStamp !== undefined &&
Date.now() - currentStamp <= PENDING_FORCE_REFRESH_TTL_MS
);
}
// 5min — same as Codex. Expiry is lazy on read (`isPendingForceRefresh`);
// this timer only reaps keys nobody fetches after the 5min TTL.
// Auto-cleanup stale entries — same shape as codexQuotaFetcher.
const _cacheCleanup = setInterval(() => {
const now = Date.now();
for (const [key, entry] of cache) {
if (now - entry.fetchedAt > CACHE_TTL_MS * 5) cache.delete(key);
}
for (const key of pendingForceRefresh.keys()) {
dropExpiredPendingForceRefresh(key, now);
}
}, 5 * 60_000);
if (typeof _cacheCleanup === "object" && "unref" in _cacheCleanup) {
(_cacheCleanup as { unref?: () => void }).unref?.();
@@ -317,47 +217,24 @@ function normalizeQuotaWindows(
export const fetchGenericQuota: QuotaFetcher = async (connectionId, connection) => {
if (!connection) return null;
const conn = connection as ConnectionInputs;
const provider = typeof conn.provider === "string" ? conn.provider.trim() : "";
const provider = typeof conn.provider === "string" ? conn.provider : null;
if (!provider) return null;
const key = cacheKey(provider, connectionId);
const now = Date.now();
const forceRefresh = isPendingForceRefresh(key, now);
const hit = cachedQuotaIfFresh(key, forceRefresh, now);
if (hit) return hit;
// convert-null / throw keep the force-refresh flag (agy inner caches are
// still stale) but must not hammer those endpoints on every routing tick.
if (isForceRefreshMissCooling(key, forceRefresh, now)) return null;
// Capture before await: a 429 during fetchUsage re-stamps this; writing
// the pre-429 snapshot would wipe that flag and recache stale quota.
const refreshStamp = pendingForceRefresh.get(key);
const cached = cache.get(key);
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
return cached.quota;
}
let usage: unknown;
try {
const fetchUsage = usageFetcherOverride ?? getUsageForProvider;
usage = await fetchUsage(conn as Parameters<typeof getUsageForProvider>[0], {
...(forceRefresh ? { forceRefresh: true } : {}),
});
usage = await getUsageForProvider(conn as Parameters<typeof getUsageForProvider>[0]);
} catch {
markPendingForceRefreshMiss(key);
return null;
}
const quota = convertUsageToQuotaInfo(usage);
if (!quota) {
markPendingForceRefreshMiss(key);
return null;
}
// Concurrent 429 re-stamped a still-live flag — do not recache the
// pre-429 snapshot. A vanished or expired stamp is not a 429.
if (isConcurrentForceRefresh(key, refreshStamp)) {
return quota;
}
pendingForceRefresh.delete(key);
pendingForceRefreshMiss.delete(key);
if (!quota) return null;
// Refresh the static window catalog so the dashboard can render the right
// modal inputs without waiting for the user to open the page.
@@ -373,33 +250,7 @@ export const fetchGenericQuota: QuotaFetcher = async (connectionId, connection)
* fresh data instead of a 60s stale window.
*/
export function invalidateGenericQuotaCache(provider: string, connectionId: string): void {
const key = cacheKey(provider, connectionId);
cache.delete(key);
// Next fetch must bypass provider-inner usage caches (agy retrieveUserQuota /
// weekly are 60s5min). Without this, dropping the 60s wrapper recaches stale.
// TTL matches those inner caches: after 5min the flag is a no-op.
pendingForceRefresh.set(key, Date.now());
pendingForceRefreshMiss.delete(key);
}
/**
* Drop the generic quota cache after an upstream 429, matching Codex's
* `invalidateCodexQuotaCache` on 429. Probe-origin failures must not mutate
* routing caches (#9817).
*/
export function invalidateGenericQuotaCacheOnStatus(args: {
provider: string | null | undefined;
connectionId: string | null | undefined;
status: number;
isolateProbe?: boolean;
}): boolean {
if (args.isolateProbe === true) return false; // undefined from callers that omit isolateProbe must still invalidate
if (args.status !== 429) return false;
const provider = typeof args.provider === "string" ? args.provider.trim() : "";
const connectionId = typeof args.connectionId === "string" ? args.connectionId.trim() : "";
if (!provider || !connectionId) return false;
invalidateGenericQuotaCache(provider, connectionId);
return true;
cache.delete(cacheKey(provider, connectionId));
}
/**

View File

@@ -1,229 +0,0 @@
/**
* moonshotQuotaFetcher.ts — Moonshot Open Platform balance quota fetcher
*
* GET {origin}/v1/users/me/balance
* { code: 0, data: { available_balance, voucher_balance, cash_balance } }
*
* Origin comes from the connection baseUrl (api.moonshot.cn or api.moonshot.ai).
* Do not hardcode .ai as a fallback for .cn keys.
*
* Cache: 60s in-memory. Registration: registerMoonshotQuotaFetcher() at startup.
*/
import { toNumber } from "@/shared/utils/numeric";
import { registerQuotaFetcher, type QuotaInfo } from "./quotaPreflight.ts";
import { registerMonitorFetcher } from "./quotaMonitor.ts";
import { throttleQuotaFetch } from "./quotaFetchThrottle.ts";
import {
isMoonshotOpenPlatformConnection,
moonshotBalanceUrl,
resolveMoonshotOrigin,
} from "./usage/moonshotOpenPlatform.ts";
import type { UsageQuota } from "./usage/quota.ts";
const CACHE_TTL_MS = 60_000;
export interface MoonshotQuota extends QuotaInfo {
availableBalance: number;
voucherBalance: number;
cashBalance: number;
origin: string;
limitReached: boolean;
}
interface CacheEntry {
quota: MoonshotQuota;
fetchedAt: number;
}
const quotaCache = new Map<string, CacheEntry>();
const _cacheCleanup = setInterval(() => {
const now = Date.now();
for (const [key, entry] of quotaCache) {
if (now - entry.fetchedAt > CACHE_TTL_MS * 5) {
quotaCache.delete(key);
}
}
}, 5 * 60_000);
if (typeof _cacheCleanup === "object" && "unref" in _cacheCleanup) {
(_cacheCleanup as { unref?: () => void }).unref?.();
}
function toRecord(value: unknown): Record<string, unknown> {
return value && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>)
: {};
}
function parseMoonshotQuotaResponse(data: unknown, origin: string): MoonshotQuota | null {
const obj = toRecord(data);
const code = obj.code;
if (code !== 0 && code !== undefined) return null;
const payload = toRecord(obj.data);
if (!("available_balance" in payload) && !("availableBalance" in payload)) return null;
const availableBalance = toNumber(payload.available_balance ?? payload.availableBalance, 0);
const voucherBalance = toNumber(payload.voucher_balance ?? payload.voucherBalance, 0);
const cashBalance = toNumber(payload.cash_balance ?? payload.cashBalance, 0);
const limitReached = availableBalance <= 0;
const percentUsed = limitReached ? 1 : 0;
return {
used: percentUsed * 100,
total: 100,
percentUsed,
resetAt: null,
availableBalance,
voucherBalance,
cashBalance,
origin,
limitReached,
windows: { balance: { percentUsed, resetAt: null } },
};
}
function connectionApiKey(connection?: Record<string, unknown>): string | null {
const apiKey = connection?.apiKey;
return typeof apiKey === "string" && apiKey.trim().length > 0 ? apiKey : null;
}
export async function fetchMoonshotQuota(
connectionId: string,
connection?: Record<string, unknown>
): Promise<QuotaInfo | null> {
const cached = quotaCache.get(connectionId);
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
return cached.quota;
}
const apiKey = connectionApiKey(connection);
if (!apiKey) return null;
const origin = resolveMoonshotOrigin({
provider: typeof connection?.provider === "string" ? connection.provider : undefined,
providerSpecificData: connection?.providerSpecificData,
});
if (!origin) return null;
const url = moonshotBalanceUrl(origin);
const authHeader = ["Bearer", apiKey].join(" ");
try {
await throttleQuotaFetch();
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: authHeader,
"Content-Type": "application/json",
Accept: "application/json",
},
signal: AbortSignal.timeout(8_000),
});
if (response.status === 401 || response.status === 403) {
quotaCache.delete(connectionId);
return null;
}
if (!response.ok) return null;
const data = await response.json();
const quota = parseMoonshotQuotaResponse(data, origin);
if (!quota) return null;
quotaCache.set(connectionId, { quota, fetchedAt: Date.now() });
return quota;
} catch {
return null;
}
}
export function invalidateMoonshotQuotaCache(connectionId: string): void {
quotaCache.delete(connectionId);
}
export type MoonshotUsageConnection = {
id?: string;
provider?: string;
apiKey?: string;
providerSpecificData?: unknown;
};
export async function getMoonshotOpenPlatformUsage(
connection: MoonshotUsageConnection
): Promise<{
plan?: string;
quotas?: Record<string, UsageQuota>;
message?: string;
limitReached?: boolean;
}> {
const origin = resolveMoonshotOrigin(connection);
if (!origin) {
return { message: "Not a Moonshot Open Platform connection." };
}
const quota = (await fetchMoonshotQuota(connection.id || "moonshot", {
apiKey: connection.apiKey,
provider: connection.provider,
providerSpecificData: connection.providerSpecificData,
})) as MoonshotQuota | null;
if (!quota) {
return { message: "Moonshot API key not available. Add a key to view usage." };
}
const domestic = origin.includes("moonshot.cn");
return {
plan: domestic ? "Kimi 开放平台(国内)" : "Kimi Open Platform",
quotas: buildMoonshotBalanceQuotas(quota, domestic ? "CNY" : "USD"),
limitReached: quota.limitReached,
};
}
function balanceQuota(
remaining: number,
remainingPercentage: number,
currency: string
): UsageQuota {
return {
used: 0,
total: 0,
remaining,
remainingPercentage,
resetAt: null,
unlimited: true,
currency,
};
}
function buildMoonshotBalanceQuotas(
quota: MoonshotQuota,
currency: string
): Record<string, UsageQuota> {
return {
available: balanceQuota(quota.availableBalance, quota.limitReached ? 0 : 100, currency),
voucher: balanceQuota(quota.voucherBalance, 100, currency),
cash: balanceQuota(quota.cashBalance, 100, currency),
};
}
export function registerMoonshotQuotaFetcher(): void {
registerQuotaFetcher("moonshot", fetchMoonshotQuota);
registerQuotaFetcher("kimi", fetchMoonshotQuota);
registerMonitorFetcher("moonshot", fetchMoonshotQuota);
registerMonitorFetcher("kimi", fetchMoonshotQuota);
}
export function registerMoonshotFetchersForNodes(
nodes: Array<{ id?: string | null; prefix?: string | null; baseUrl?: string | null }>
): void {
for (const node of nodes) {
const origin = resolveMoonshotOrigin({}, node.baseUrl);
if (!origin) continue;
if (typeof node.id === "string" && node.id) {
registerQuotaFetcher(node.id, fetchMoonshotQuota);
registerMonitorFetcher(node.id, fetchMoonshotQuota);
}
if (typeof node.prefix === "string" && node.prefix) {
registerQuotaFetcher(node.prefix, fetchMoonshotQuota);
registerMonitorFetcher(node.prefix, fetchMoonshotQuota);
}
}
}
export { isMoonshotOpenPlatformConnection };

View File

@@ -21,22 +21,12 @@
import { isCompatibleProviderConnectionId } from "@/shared/utils/compatibleProviderId";
import { isFeatureFlagEnabled } from "@/shared/utils/featureFlags";
import { fetchNewApiAggregatorQuota } from "./newApiAggregatorQuotaFetcher.ts";
import {
isAntigravityQuotaProvider,
selectAntigravityQuotaWindowNames,
} from "./antigravityQuotaFamily.ts";
export interface PreflightQuotaResult {
proceed: boolean;
reason?: string;
quotaPercent?: number;
resetAt?: string | null;
windowName?: string | null;
}
export interface QuotaCutoffScope {
provider?: string | null;
requestedModel?: string | null;
}
export interface QuotaWindowInfo {
@@ -166,36 +156,15 @@ function isRemainingAtOrBelowThreshold(
return remainingPercent <= thresholdPercent + REMAINING_PERCENT_EPSILON;
}
function exhaustedResult(
quotaPercent: number,
resetAt: string | null,
windowName?: string | null
): PreflightQuotaResult {
function exhaustedResult(quotaPercent: number, resetAt: string | null): PreflightQuotaResult {
return {
proceed: false,
reason: "quota_exhausted",
quotaPercent,
resetAt,
windowName: windowName ?? null,
};
}
function windowsForScope(
windows: NonNullable<QuotaInfo["windows"]>,
scope?: QuotaCutoffScope
): NonNullable<QuotaInfo["windows"]> {
if (!scope?.requestedModel || !isAntigravityQuotaProvider(scope.provider ?? null)) {
return windows;
}
const selected = selectAntigravityQuotaWindowNames(Object.keys(windows), scope.requestedModel);
if (selected.length === 0) return windows;
const scoped: NonNullable<QuotaInfo["windows"]> = {};
for (const name of selected) {
if (windows[name]) scoped[name] = windows[name];
}
return Object.keys(scoped).length > 0 ? scoped : windows;
}
function limitReachedResult(quota: QuotaInfo): PreflightQuotaResult {
return exhaustedResult(
Number.isFinite(quota.percentUsed) ? quota.percentUsed : 1,
@@ -232,9 +201,7 @@ function quotaWindowCutoffResult(
worstResetAt = windowInfo.resetAt ?? null;
}
return worstWindow === null
? null
: exhaustedResult(worstUsedPercent, worstResetAt, worstWindow);
return worstWindow === null ? null : exhaustedResult(worstUsedPercent, worstResetAt);
}
function quotaPercentCutoffResult(
@@ -260,27 +227,21 @@ function quotaPercentCutoffResult(
*/
export function evaluateQuotaCutoff(
quota: QuotaInfo | null | undefined,
thresholds?: PreflightQuotaThresholds,
scope?: QuotaCutoffScope
thresholds?: PreflightQuotaThresholds
): PreflightQuotaResult {
if (!quota) return { proceed: true };
if (quota.limitReached === true) return limitReachedResult(quota);
const windows = quota.windows;
if (windows && Object.keys(windows).length > 0) {
const scopedWindows = windowsForScope(windows, scope);
const cutoff = quotaWindowCutoffResult(scopedWindows, thresholds);
if (cutoff) return cutoff;
if (isAntigravityQuotaProvider(scope?.provider ?? null) && scope?.requestedModel) {
return { proceed: true, quotaPercent: quota.percentUsed };
}
if (quota.limitReached === true) return limitReachedResult(quota);
return {
proceed: true,
quotaPercent: quota.percentUsed,
};
return (
quotaWindowCutoffResult(windows, thresholds) ?? {
proceed: true,
quotaPercent: quota.percentUsed,
}
);
}
if (quota.limitReached === true) return limitReachedResult(quota);
return quotaPercentCutoffResult(quota, thresholds);
}
@@ -336,40 +297,61 @@ export async function preflightQuota(
return { proceed: true };
}
const requestedModel =
typeof connection.requestedModel === "string" ? connection.requestedModel : null;
const scope: QuotaCutoffScope = { provider, requestedModel };
const windows = quota.windows;
if (windows && Object.keys(windows).length > 0) {
const scopedWindows = windowsForScope(windows, scope);
for (const [windowName, windowInfo] of Object.entries(scopedWindows)) {
if (quota.limitReached === true) {
return limitReachedResult(quota);
}
// Per-window evaluation — only when the fetcher surfaces a windows map.
// We block as soon as ANY single window's remaining quota drops to its
// configured cutoff or below; warnings are logged independently per window.
if (quota.windows && Object.keys(quota.windows).length > 0) {
let worstUsedPercent = 0;
let worstWindow: string | null = null;
let worstResetAt: string | null = null;
for (const [windowName, windowInfo] of Object.entries(quota.windows)) {
const minRemainingPercent = resolveOrDefault(
thresholds?.resolveMinRemainingPercent,
windowName,
DEFAULT_MIN_REMAINING_PERCENT
);
const warnRemainingPercent = resolveOrDefault(
thresholds?.resolveWarnRemainingPercent,
windowName,
DEFAULT_WARN_REMAINING_PERCENT
);
const remainingPercent = remainingPercentFrom(windowInfo.percentUsed);
if (isRemainingAtOrBelowThreshold(remainingPercent, warnRemainingPercent)) {
if (isRemainingAtOrBelowThreshold(remainingPercent, minRemainingPercent)) {
// Track the most-depleted blocking window so the response can name it.
if (windowInfo.percentUsed > worstUsedPercent) {
worstUsedPercent = windowInfo.percentUsed;
worstWindow = windowName;
worstResetAt = windowInfo.resetAt ?? null;
} else if (worstWindow === null) {
worstWindow = windowName;
worstResetAt = windowInfo.resetAt ?? null;
}
} else if (isRemainingAtOrBelowThreshold(remainingPercent, warnRemainingPercent)) {
console.warn(
`[QuotaPreflight] ${provider}/${connectionId} ${windowName}: ${remainingPercent.toFixed(1)}% remaining — approaching cutoff`
);
}
}
}
const decision = evaluateQuotaCutoff(quota, thresholds, scope);
if (!decision.proceed) {
const windowLabel = decision.windowName ? ` ${decision.windowName}` : "";
const remaining = Number.isFinite(decision.quotaPercent)
? remainingPercentFrom(decision.quotaPercent as number).toFixed(1)
: "?";
console.info(
`[QuotaPreflight] ${provider}/${connectionId}${windowLabel}: ${remaining}% remaining - switching`
);
return decision;
}
if (windows && Object.keys(windows).length > 0) {
return decision;
if (worstWindow !== null) {
const worstRemaining = remainingPercentFrom(worstUsedPercent);
console.info(
`[QuotaPreflight] ${provider}/${connectionId} ${worstWindow}: ${worstRemaining.toFixed(1)}% remaining — switching`
);
return {
proceed: false,
reason: "quota_exhausted",
quotaPercent: worstUsedPercent,
resetAt: worstResetAt,
};
}
return { proceed: true, quotaPercent: quota.percentUsed };
}
// Legacy single-signal path for fetchers that don't expose per-window data.

View File

@@ -61,8 +61,6 @@ import { getQoderUsage, parseQoderUserStatusUsage } from "./usage/qoder.ts";
export { parseQoderUserStatusUsage } from "./usage/qoder.ts";
import { getOpencodeUsage } from "./usage/opencode.ts";
import { getDeepseekUsage } from "./usage/deepseek.ts";
import { getMoonshotOpenPlatformUsage } from "./moonshotQuotaFetcher.ts";
import { isMoonshotOpenPlatformConnection } from "./usage/moonshotOpenPlatform.ts";
import { getDevinCliUsage } from "./usage/devinCli.ts";
import { getBailianCodingPlanUsage } from "./usage/bailian.ts";
import { getVertexUsage } from "./usage/vertex.ts";
@@ -113,10 +111,6 @@ export async function getUsageForProvider(
) {
const { id, provider, accessToken, apiKey, providerSpecificData, projectId, email } = connection;
if (isMoonshotOpenPlatformConnection(connection)) {
return await getMoonshotOpenPlatformUsage(connection);
}
switch (provider) {
case "github":
return await getGitHubUsage(accessToken, providerSpecificData);
@@ -174,9 +168,6 @@ export async function getUsageForProvider(
return await getNanoGptUsage(apiKey || "");
case "deepseek":
return await getDeepseekUsage(id || "", apiKey || "");
case "moonshot":
case "kimi":
return await getMoonshotOpenPlatformUsage(connection);
case "openrouter":
return await getOpenrouterUsage(id || "", apiKey || "", providerSpecificData);
case "opencode":

View File

@@ -45,8 +45,6 @@ export const USAGE_FETCHER_PROVIDERS = [
"qwen-cloud-token-plan",
"nanogpt",
"deepseek",
"moonshot",
"kimi",
"opencode",
"opencode-zen",
"xiaomi-mimo",

View File

@@ -239,12 +239,9 @@ export async function getGrokCliUsage(accessToken?: string) {
const config = billing.config;
const resetAt = config.currentPeriod?.end || null;
const quotas: Record<string, ReturnType<typeof percentageQuota>> = {};
// SuperGrokPro (and proto3 omit-zero) billing configs often omit
// creditUsagePercent / productUsage. A present config object is a
// successful billing read, so treat a missing percent as 0% used and
// still render a weekly bar. A missing config still returns
// "Grok Build billing status unavailable" above — that path is unchanged.
quotas.weekly = percentageQuota(config.creditUsagePercent ?? 0, resetAt);
if (config.creditUsagePercent != null) {
quotas.weekly = percentageQuota(config.creditUsagePercent, resetAt);
}
Object.assign(quotas, buildProductQuotas(config.productUsage, resetAt));
const autoTopUpResponse = userId

View File

@@ -1,76 +0,0 @@
/**
* Moonshot Open Platform host recognition.
*
* Distinguishes prepaid Open Platform keys (api.moonshot.cn / api.moonshot.ai)
* from Kimi Coding Plan (api.kimi.com/coding). Custom compatible nodes are
* identified by baseUrl host, not by provider id (those ids are uuids).
*/
import { moonshotProvider } from "../../config/providers/registry/moonshot/index.ts";
import { kimiProvider } from "../../config/providers/registry/kimi/index.ts";
export const MOONSHOT_OPEN_PLATFORM_HOSTS: ReadonlySet<string> = new Set([
"api.moonshot.cn",
"api.moonshot.ai",
]);
export type MoonshotOriginConnection = {
provider?: string;
providerSpecificData?: unknown;
};
function asRecord(value: unknown): Record<string, unknown> {
return value && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>)
: {};
}
export function parseMoonshotOrigin(baseUrl: string | null | undefined): string | null {
if (typeof baseUrl !== "string" || baseUrl.trim() === "") return null;
let url: URL;
try {
url = new URL(baseUrl.trim());
} catch {
return null;
}
if (url.protocol !== "https:" && url.protocol !== "http:") return null;
const host = url.hostname.toLowerCase();
if (!MOONSHOT_OPEN_PLATFORM_HOSTS.has(host)) return null;
const port = url.port ? `:${url.port}` : "";
return `${url.protocol}//${host}${port}`;
}
export function moonshotBalanceUrl(origin: string): string {
return `${origin}/v1/users/me/balance`;
}
function registryDefaultOrigin(provider: string | undefined): string | null {
if (provider === "moonshot") return parseMoonshotOrigin(moonshotProvider.baseUrl);
if (provider === "kimi") return parseMoonshotOrigin(kimiProvider.baseUrl);
return null;
}
export function resolveMoonshotOrigin(
connection: MoonshotOriginConnection,
nodeBaseUrl?: string | null,
): string | null {
const psd = asRecord(connection.providerSpecificData);
const fromPsd = typeof psd.baseUrl === "string" ? parseMoonshotOrigin(psd.baseUrl) : null;
if (fromPsd) return fromPsd;
const fromNode = parseMoonshotOrigin(nodeBaseUrl);
if (fromNode) return fromNode;
return registryDefaultOrigin(connection.provider);
}
export function isMoonshotOpenPlatformConnection(
connection: MoonshotOriginConnection,
nodeBaseUrl?: string | null,
): boolean {
return resolveMoonshotOrigin(connection, nodeBaseUrl) !== null;
}
/** Account-level empty wallet on Open Platform. Narrower than any compatible 429. */
export function isMoonshotAccountBalanceExhausted(errorText: string | null | undefined): boolean {
const lower = String(errorText || "").toLowerCase();
return lower.includes("insufficient balance") || lower.includes("exceeded_current_quota");
}

View File

@@ -41,8 +41,6 @@ export const USAGE_SUPPORTED_PROVIDERS: readonly string[] = [
"crof",
"nanogpt",
"deepseek",
"moonshot",
"kimi",
"xiaomi-mimo",
"xiaomi-mimo-token-plan",
"vertex",

View File

@@ -23,12 +23,12 @@ import {
import { createEventEmitter } from "./openai-responses/eventEmitter.ts";
import { buildResponsesToolCallItem } from "./responsesToolItem.ts";
import { resolveRequestToolIdentity } from "./openai-responses/requestToolIdentity.ts";
import { resolveLocalToolCallIndex } from "./openai-responses/toolCallLocalIndex.ts";
import {
synthesizeCompletedToolCalls,
computeFinishReason,
withAssistantRoleOnFirstDelta,
} from "./openai-responses/synthesizeCompletedToolCalls.ts";
// normalizeUpstreamFailure is re-exported for external importers (tests).
export { normalizeUpstreamFailure } from "./openai-responses/pureHelpers.ts";
@@ -506,7 +506,7 @@ function toolCallOutputIndexBase(state) {
function emitToolCall(state, emit, tc) {
const tcIdx = tc.index ?? 0;
const outputIndex = toolCallOutputIndexBase(state) + resolveLocalToolCallIndex(state, tcIdx);
const outputIndex = toolCallOutputIndexBase(state) + normalizeOutputIndex(tcIdx);
const newCallId = tc.id;
const funcName = tc.function?.name;
@@ -609,7 +609,7 @@ function emitToolCall(state, emit, tc) {
function closeToolCall(state, emit, idx, recordAsCompleted = true) {
const callId = state.funcCallIds[idx];
if (callId && !state.funcItemDone[idx]) {
const normalizedIndex = toolCallOutputIndexBase(state) + resolveLocalToolCallIndex(state, idx);
const normalizedIndex = toolCallOutputIndexBase(state) + normalizeOutputIndex(idx);
const args = state.funcArgsBuf[idx] || "{}";
const toolName = state.funcNames[idx] || "";
// See emitToolCall()'s isCustomTool comment — must stay in sync (both compute the

View File

@@ -1,35 +0,0 @@
/**
* Remap a turn's raw upstream tool_calls delta `index` onto a local,
* contiguous, 0-based sequence in first-seen order.
*
* Live incident (2026-09-02, minimax-m3:free via OpenRouter/GMICloud): the
* upstream's own `index` doesn't reliably start at 0 or stay contiguous per
* turn — this turn's two calls arrived with raw index 1 and 2 (never 0).
* Adding that raw index straight onto toolCallOutputIndexBase() left a GAP
* in the emitted output_index sequence (0 for the message, then 2 and 3 for
* the calls — index 1 never used). A client that reads response.completed's
* final `output[]` array by ARRAY POSITION and expects position to equal
* output_index (the Responses API's own contract) reads output[1] (this
* turn's first call, real output_index 2) while looking it up under
* output_index 1, misses it, then reads output[2] (the second call, real
* output_index 3) under output_index 2 — landing on the FIRST call's tracked
* slot with a different call_id, which a spec-following client correctly
* treats as "stream changed output item identity" and aborts.
*/
export type ToolCallLocalIndexState = {
toolCallLocalIndex?: Record<string, number>;
toolCallLocalIndexNext?: number;
};
export function resolveLocalToolCallIndex(
state: ToolCallLocalIndexState,
tcIdx: string | number
): number {
if (!state.toolCallLocalIndex) state.toolCallLocalIndex = {};
if (state.toolCallLocalIndex[tcIdx] === undefined) {
state.toolCallLocalIndex[tcIdx] = state.toolCallLocalIndexNext ?? 0;
state.toolCallLocalIndexNext = state.toolCallLocalIndex[tcIdx] + 1;
}
return state.toolCallLocalIndex[tcIdx];
}

View File

@@ -67,47 +67,9 @@ function requireDuration(name: string, value: number): number {
return value;
}
/**
* Human-readable key=value detail appended to the rejection log line. Every
* rejection (immediate heap trip AND cached-critical-state reuse) goes
* through here, so this is the one place that needs the actual numbers —
* the bare reason code alone ("psi_some") gives an operator nothing to act
* on when deciding whether the guard is mistuned vs. genuinely saturated.
*/
function formatPressureDetail(detail: Record<string, number | string | null | undefined>): string {
return Object.entries(detail)
.filter(([, value]) => value !== undefined)
.map(([key, value]) => `${key}=${value ?? "null"}`)
.join(" ");
}
/** Builds buildCriticalGuard's detail object for the cached-critical-state
* reuse path in check() -- pulled out of check() itself so that function's
* own cyclomatic complexity stays under the ratchet, not because this needs
* to be reused anywhere else. */
function describeCachedPressure(params: {
signals: ResourceSignals | null;
recoveryStreak: number;
cacheAgeMs: number;
}): Record<string, number | string | null> {
const cgroup = params.signals?.cgroup;
return {
psiSomeAvg10: params.signals?.psi?.someAvg10 ?? null,
psiFullAvg10: params.signals?.psi?.fullAvg10 ?? null,
cgroupCurrentMb: cgroup?.currentBytes ? Math.round(cgroup.currentBytes / MB) : null,
cgroupMaxMb: cgroup?.maxBytes ? Math.round(cgroup.maxBytes / MB) : null,
recoveryStreak: params.recoveryStreak,
sampleAgeMs: params.cacheAgeMs,
};
}
function buildCriticalGuard(
reason: PressureReason,
detail: Record<string, number | string | null | undefined> = {}
): ResourcePressureGuardResult {
const detailText = formatPressureDetail(detail);
function buildCriticalGuard(reason: PressureReason): ResourcePressureGuardResult {
console.warn(
`[resourcePressure] critical pressure guard tripped (reason=${reason}${detailText ? " " + detailText : ""}); returning 503`
`[resourcePressure] critical pressure guard tripped (reason=${reason}); returning 503`
);
return {
success: false,
@@ -135,10 +97,7 @@ function immediateHeapGuard(
if (thresholdMb == null) return null;
const guard = checkHeapPressureGuard(heapUsedMb, thresholdMb);
if (!guard) return null;
return buildCriticalGuard("v8_heap_absolute", {
heapUsedMb: Math.round(heapUsedMb),
thresholdMb: Math.round(thresholdMb),
});
return buildCriticalGuard("v8_heap_absolute");
}
export function createResourcePressureRuntime(
@@ -233,17 +192,9 @@ export function createResourcePressureRuntime(
return immediate;
}
const cacheAge = lastSignals ? Math.max(0, now - lastRefreshAtMs) : Number.POSITIVE_INFINITY;
if (cacheAge > maxStaleMs || state.severity !== "critical") {
return null;
}
return buildCriticalGuard(
state.reason,
describeCachedPressure({
signals: lastSignals,
recoveryStreak: state.recoveryStreak,
cacheAgeMs: cacheAge,
})
);
return cacheAge <= maxStaleMs && state.severity === "critical"
? buildCriticalGuard(state.reason)
: null;
},
getObservation: () => ({ signals: lastSignals, state }),
whenRefreshSettled: async () => {

Some files were not shown because too many files have changed in this diff Show More