mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-15 03:32:21 +03:00
Compare commits
34 Commits
docs/audit
...
fix/radar-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2d2598a0d | ||
|
|
dfcf6086a2 | ||
|
|
6233ca6642 | ||
|
|
45a4358b61 | ||
|
|
6cad6314b5 | ||
|
|
bac3b4eb37 | ||
|
|
7580feb1bf | ||
|
|
be04c7aecb | ||
|
|
834e53b95b | ||
|
|
da148eddb7 | ||
|
|
3784c35b29 | ||
|
|
74f146a7d4 | ||
|
|
2256057f4a | ||
|
|
b314b1b112 | ||
|
|
b334d2d05a | ||
|
|
baa68bfc06 | ||
|
|
d0aff219f5 | ||
|
|
6f48ac4bfe | ||
|
|
e80ac605bc | ||
|
|
1a55b20963 | ||
|
|
a45076fa2a | ||
|
|
7859c843de | ||
|
|
b8a6557449 | ||
|
|
fa7bf4df7b | ||
|
|
f806740a2f | ||
|
|
e2e589c79c | ||
|
|
b11d55332b | ||
|
|
ee6695acad | ||
|
|
b6bba896b3 | ||
|
|
ea95cc2937 | ||
|
|
a801abc8e9 | ||
|
|
86caa94baa | ||
|
|
2ebab9c686 | ||
|
|
340edbc997 |
11
.env.example
11
.env.example
@@ -2652,9 +2652,9 @@ QUOTA_STORE_DRIVER=sqlite
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# Optional add-on (feature flag RADAR_ENABLED, default off — see feature flag
|
||||
# settings, not an env var) that overlays a signed, freshly-curated free-model
|
||||
# catalog on top of the release baseline. All four variables below are optional
|
||||
# and only needed to point the client at a self-hosted/forked feed or
|
||||
# supporter-key flow instead of the default OmniRoute Radar service. Used by:
|
||||
# catalog on top of the release baseline. The first four variables below are
|
||||
# optional overrides for a self-hosted/forked feed or supporter-key flow. The
|
||||
# fifth is an optional, default-free link to the owner's private operations panel. Used by:
|
||||
# src/lib/radar/sync.ts, src/lib/radar/pinnedKeys.ts, src/lib/radar/links.ts.
|
||||
|
||||
# Base URL of the Radar feed service. Overrides the built-in default so forks
|
||||
@@ -2675,6 +2675,11 @@ QUOTA_STORE_DRIVER=sqlite
|
||||
# page). No pricing/value lives in this repo — only the link.
|
||||
# RADAR_SUPPORTER_PLANS_URL=https://radar.omniroute.online/planos
|
||||
|
||||
# Owner-only link to the private Radar operations panel. There is deliberately
|
||||
# no default: when unset or invalid, no "Radar Admin" navigation item exists.
|
||||
# Use HTTPS for a tunnel/tailnet URL, or HTTP only for an SSH loopback forward.
|
||||
# RADAR_ADMIN_URL=http://127.0.0.1:9351
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# 27. RELEASE v3.8.50 ADDITIONS
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@@ -18,7 +18,7 @@ Vitest, the 60% coverage gate, and the production build all run in CI on this PR
|
||||
- [ ] `npm run lint`
|
||||
- [ ] Reconciled with the current active release base; focused checks rerun afterward
|
||||
- [ ] Production-code changes include a new or updated automated test in this PR
|
||||
- [ ] SonarQube PR analysis is green or any remaining issues are explicitly documented below
|
||||
- SonarQube is temporarily opt-in while the private project has no quota; it is not a PR gate.
|
||||
|
||||
## Tests Added Or Updated
|
||||
|
||||
|
||||
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@@ -998,7 +998,10 @@ jobs:
|
||||
name: SonarQube
|
||||
runs-on: ubuntu-latest
|
||||
needs: test-coverage
|
||||
if: ${{ !cancelled() && needs.test-coverage.result == 'success' }}
|
||||
# Temporarily opt-in: the private project currently has no Sonar quota.
|
||||
# Re-enable without another code change by setting the repository Actions
|
||||
# variable SONARQUBE_ENABLED=true after quota/project access is restored.
|
||||
if: ${{ vars.SONARQUBE_ENABLED == 'true' && !cancelled() && needs.test-coverage.result == 'success' }}
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
||||
@@ -1397,7 +1400,7 @@ jobs:
|
||||
echo "| i18n UI Coverage | $(status '${{ needs.i18n-ui-coverage.result }}') |" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "| i18n Glossary (zh-CN, ko) | $(status '${{ needs.i18n-glossary-zhcn.result }}') |" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "| PR Test Policy | $(status '${{ needs.pr-test-policy.result }}') |" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "| SonarQube | $(status '${{ needs.sonarqube.result }}') |" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "| SonarQube (opt-in; disabled without SONARQUBE_ENABLED=true) | $(status '${{ needs.sonarqube.result }}') |" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
echo "" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "## 🏗️ Build" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
43
AGENTS.md
43
AGENTS.md
@@ -48,20 +48,20 @@ Repository map and Reference Documentation sections below.
|
||||
|
||||
**OmniRoute** — unified AI proxy/router. One endpoint, 339 LLM providers, auto-fallback.
|
||||
|
||||
| Layer | Location | Purpose |
|
||||
| ------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| API Routes | `src/app/api/v1/` | Next.js App Router — entry points |
|
||||
| Handlers | `open-sse/handlers/` | Request processing (chat, embeddings, etc) |
|
||||
| Executors | `open-sse/executors/` | Provider-specific HTTP dispatch |
|
||||
| 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 (145 migrations) |
|
||||
| Domain/Policy | `src/domain/` | Policy engine, cost rules, fallback logic |
|
||||
| MCP Server | `open-sse/mcp-server/` | 105 tools (43 base + memory/skill/agentSkill/pool/notion/obsidian/gamification/plugin modules), 3 transports (stdio / SSE / Streamable HTTP), 31 scopes |
|
||||
| A2A Server | `src/lib/a2a/` | JSON-RPC 2.0 agent protocol |
|
||||
| Skills | `src/lib/skills/` | Extensible skill framework |
|
||||
| Memory | `src/lib/memory/` | Persistent conversational memory |
|
||||
| Layer | Location | Purpose |
|
||||
| ------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| API Routes | `src/app/api/v1/` | Next.js App Router — entry points |
|
||||
| Handlers | `open-sse/handlers/` | Request processing (chat, embeddings, etc) |
|
||||
| Executors | `open-sse/executors/` | Provider-specific HTTP dispatch |
|
||||
| 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 (148 migrations) |
|
||||
| Domain/Policy | `src/domain/` | Policy engine, cost rules, fallback logic |
|
||||
| MCP Server | `open-sse/mcp-server/` | 109 tools (44 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 |
|
||||
| Skills | `src/lib/skills/` | Extensible skill framework |
|
||||
| Memory | `src/lib/memory/` | Persistent conversational memory |
|
||||
|
||||
Monorepo: `src/` (Next.js 16 app), `open-sse/` (streaming engine workspace), `electron/` (desktop app), `tests/`, `bin/` (CLI entry point).
|
||||
|
||||
@@ -118,18 +118,11 @@ upstream/service level, so one unhealthy provider does not slow down every reque
|
||||
- `HALF_OPEN`: reset timeout has elapsed; allow a probe request. Success closes the
|
||||
breaker, failure opens it again.
|
||||
|
||||
**Defaults** (`open-sse/config/constants.ts` → `PROVIDER_PROFILES`). Two thresholds live side by
|
||||
side — do not confuse them:
|
||||
**Defaults** (`open-sse/config/constants.ts`):
|
||||
|
||||
| Profile | `providerFailureThreshold` (whole provider) | `providerCooldownMs` | `circuitBreakerThreshold` (one connection) | `circuitBreakerReset` |
|
||||
| ------- | ------------------------------------------: | -------------------: | -----------------------------------------: | --------------------: |
|
||||
| OAuth | `10` | `5min` | `8` | `60s` |
|
||||
| API key | `15` | `10min` | `12` | `30s` |
|
||||
| Local | `2` | `1min` | `2` | `15s` |
|
||||
|
||||
The provider-level thresholds were scaled up for deployments with 500+ connections (OAuth was
|
||||
`3`, API key was `5`); every default is overridable through the `OMNIROUTE_PROVIDER_BREAKER_*`
|
||||
and `OMNIROUTE_CIRCUIT_BREAKER_*` env vars.
|
||||
- OAuth providers: threshold `3`, reset timeout `60s`.
|
||||
- API-key providers: threshold `5`, reset timeout `30s`.
|
||||
- Local providers: threshold `2`, reset timeout `15s`.
|
||||
|
||||
Only provider-level failure statuses should trip the provider breaker:
|
||||
|
||||
|
||||
772
CHANGELOG.md
772
CHANGELOG.md
@@ -9,7 +9,6 @@
|
||||
_Living section — regenerated 2026-08-12 from all cycle commits (cycle open `ed2db6cb19` → tip). Bullets carry the merged PR and its author; direct pushes listed separately._
|
||||
|
||||
### ✨ New Features
|
||||
|
||||
- **feat(core):** add Layer A capability filter at router (#5696)
|
||||
- **feat(providers):** add DeepAI as paid API-key image provider ([#6671](https://github.com/diegosouzapw/OmniRoute/issues/6671))
|
||||
- **feat(providers):** add Naga.ac and ChatAnywhere aggregator gateway providers (#6674 — thanks @chirag127)
|
||||
@@ -32,7 +31,7 @@ _Living section — regenerated 2026-08-12 from all cycle commits (cycle open `e
|
||||
- **Providers**: expands the Novita AI catalog from a single Llama 3.1 8B entry to 19 curated serving models (DeepSeek V4, Kimi K3, GLM 5.2, MiniMax M3, Qwen3.7 Max, Qwen3 Coder 480B, MiMo V2.5 Pro, gpt-oss-120b, Gemma 4 31B and more), each carrying its real context window, output cap and reasoning flag from the live `/openai/v1/models` listing, and each vision flag confirmed by an actual image request rather than the listing's self-reported modalities ([#8913](https://github.com/diegosouzapw/OmniRoute/pull/8913)) — thanks @jax-novita
|
||||
- **feat(providers):** native xAI Agent Tools passthrough on `/v1/responses` for `xai` / `xai-oauth` (`xao`) — forward `web_search` + `x_search` to `api.x.ai` instead of rewriting or rejecting them ([#8964](https://github.com/diegosouzapw/OmniRoute/issues/8964))
|
||||
- **feat(providers): add UnoRouter provider** — UnoRouter is an OpenAI-compatible routing gateway supporting hundreds of models. It is now registered as an API-key provider. ([#8978](https://github.com/diegosouzapw/OmniRoute/issues/8978))
|
||||
- **feat(sse):** deprecated the legacy `gemini-cli` **upstream provider**. It was not routable (no registry entry, no executor), yet the scheduler kept refreshing its token against Google — maintaining a credential that could never serve a request. A stored connection now becomes terminal with a legible reason and a working migration path: re-add the account under `gemini`, which uses the same Google OAuth client. The `gemini-cli` **client identity** (requests arriving _from_ the Gemini CLI, issue #7034) is untouched ([#8980](https://github.com/diegosouzapw/OmniRoute/pull/8980))
|
||||
- **feat(sse):** deprecated the legacy `gemini-cli` **upstream provider**. It was not routable (no registry entry, no executor), yet the scheduler kept refreshing its token against Google — maintaining a credential that could never serve a request. A stored connection now becomes terminal with a legible reason and a working migration path: re-add the account under `gemini`, which uses the same Google OAuth client. The `gemini-cli` **client identity** (requests arriving *from* the Gemini CLI, issue #7034) is untouched ([#8980](https://github.com/diegosouzapw/OmniRoute/pull/8980))
|
||||
- Add a default-off connection setting for Codex, OpenAI, and OpenAI-compatible Responses API providers that preserves client-supplied `reasoning.encrypted_content` items for replay, including per-target combo routing.
|
||||
- Omit opaque encrypted reasoning values from persisted call logs while retaining compact diagnostic markers. (#9000)
|
||||
- **feat(providers):** add Regolo AI OpenAI-compatible provider ([#9031](https://github.com/diegosouzapw/OmniRoute/issues/9031))
|
||||
@@ -45,7 +44,6 @@ _Living section — regenerated 2026-08-12 from all cycle commits (cycle open `e
|
||||
- feat(images): execute full combo strategy + fallback in /v1/images/generations (#9239)
|
||||
|
||||
Adds open-sse/services/imageCombo.ts that expands combo targets, filters to images-capable, executes the priority strategy with handleImageGeneration per target, and returns the first success or last failure. Route patches detect combo names before model resolution and divert to the new execution path.
|
||||
|
||||
- feat: make forwarded upstream response-header budget configurable via env var (#9243)
|
||||
- **feat(providers):** filter provider detail connections server-side while preserving full-page search and pagination. (thanks @RobertsXML) ([#9247](https://github.com/diegosouzapw/OmniRoute/pull/9247))
|
||||
- **feat(providers):** make video_url passthrough configurable per provider/model via compat override ([#9248](https://github.com/diegosouzapw/OmniRoute/issues/9248)) — thanks @HellFiveOsborn
|
||||
@@ -63,7 +61,6 @@ _Living section — regenerated 2026-08-12 from all cycle commits (cycle open `e
|
||||
- feat(opencode-plugin): warm catalog startup from disk snapshot + parallel refresh (#9490)
|
||||
|
||||
The config-shim hook now reads the last disk snapshot before fetching, so the provider registers immediately with the last-known-good catalog (~1-2s vs ~30s on a warm gateway). All six fetchers run concurrently via Promise.allSettled instead of sequentially. A failed refresh keeps the snapshot (no overwrite). An in-flight guard prevents concurrent refreshes for the same cache key. The features.diskCache: false opt-out disables the warm read entirely.
|
||||
|
||||
- **feat(models):** Test All's "Auto-hide failed models" no longer hides quota errors — daily-quota-exhausted and credits-exhausted responses are now classified via the routing path's existing quota detectors, so an evening Test All on a free-tier provider no longer silently wipes the catalog. Quota results stay visible with a distinct amber badge ([#9511](https://github.com/diegosouzapw/OmniRoute/issues/9511))
|
||||
- Add an advisory forgotten-sibling-tests report to pull-request quality checks. The report traces changed modules through their static consumers to candidate sibling tests, while keeping barrel and dynamic-import cases non-blocking and requiring reviewed, referenced exceptions. (#9530)
|
||||
- feat(providers): add Muse Code CLI provider preset (#9544)
|
||||
@@ -79,7 +76,6 @@ _Living section — regenerated 2026-08-12 from all cycle commits (cycle open `e
|
||||
`model`, `provider`, `errorCode`.
|
||||
|
||||
Non-breaking — existing `onResponse` hooks with `{ streamed: true }` remain unchanged.
|
||||
|
||||
- **feat(audio):** Soniox STT + TTS provider (`sx`) — async speech-to-text (`stt-async-v5`, `stt-async-v4`) and real-time text-to-speech (`tts-rt-v1`) ([#9579](https://github.com/diegosouzapw/OmniRoute/pull/9579))
|
||||
- Show cache-read and cache-write token counts in request log rows and details when providers
|
||||
report them. (#9620)
|
||||
@@ -152,22 +148,6 @@ _Living section — regenerated 2026-08-12 from all cycle commits (cycle open `e
|
||||
- **feat(admission) — direct pushes:** adaptive overload/pressure controls with shared admission wired across the LLM routes, plus mutation-test registration for the capability-filter suite
|
||||
- **feat(agentrouter) — direct pushes:** support Claude and Codex protocols — infer the protocol from the client endpoint and honor the alternate protocol through the chat pipeline
|
||||
- **feat(providers) — direct pushes:** ChatGPT Web session credential guide with a Cookie Editor fast-path (canonical chromewebstore install link) and web-session fast-path test coverage
|
||||
- **feat(sse):** honor provider-rule lock scope for agentrouter (connection vs model) ([#10419](https://github.com/diegosouzapw/OmniRoute/pull/10419))
|
||||
- **feat(ocr):** Vertex AI DeepSeek-OCR provider ([#10398](https://github.com/diegosouzapw/OmniRoute/pull/10398))
|
||||
- **feat(providers):** derive imageToText from the OCR registry + chutes dots.ocr seed ([#10400](https://github.com/diegosouzapw/OmniRoute/pull/10400))
|
||||
- **feat(ocr):** multi-provider /v1/ocr with transformation layer (Azure Document Intelligence) ([#10283](https://github.com/diegosouzapw/OmniRoute/pull/10283))
|
||||
- **feat(providers):** declare imageToText serviceKind on major vision providers ([#10275](https://github.com/diegosouzapw/OmniRoute/pull/10275))
|
||||
- **feat(bridge):** native-vision skip guard + configurable describe output cap ([#10289](https://github.com/diegosouzapw/OmniRoute/pull/10289))
|
||||
- **feat(bridge):** normalize images to 2048px long edge before vision describe self-call ([#10287](https://github.com/diegosouzapw/OmniRoute/pull/10287))
|
||||
- **feat(sse):** restate agentrouter quota 403/400 as retryable 429 with provider-scoped error rules ([#10335](https://github.com/diegosouzapw/OmniRoute/pull/10335))
|
||||
- **feat(sse):** add i-have-adhd output style to compression catalog ([#10271](https://github.com/diegosouzapw/OmniRoute/pull/10271))
|
||||
- **feat(codex):** add OAuth fingerprint convergence modes ([#10243](https://github.com/diegosouzapw/OmniRoute/pull/10243)) — thanks @xz-dev
|
||||
- **feat(i18n):** complete Portuguese (PT-PT) translation ([#10250](https://github.com/diegosouzapw/OmniRoute/pull/10250)) — thanks @DarkEsteves
|
||||
- **feat(providers):** publish Poolside's probed Laguna Preview catalog ([#10216](https://github.com/diegosouzapw/OmniRoute/pull/10216)) — thanks @pacocartones
|
||||
- **feat(crof):** advertise reasoning effort tiers incl. max from live discovery and registry ([#10062](https://github.com/diegosouzapw/OmniRoute/pull/10062)) — thanks @excessivechaos
|
||||
- **feat(open-sse):** expose provider-level circuit breaker thresholds via env vars (#10040) ([#10046](https://github.com/diegosouzapw/OmniRoute/pull/10046)) — thanks @tiangao88
|
||||
- **feat(dashboard):** Kimi 15% first-top-up campaign — dedicated tracked link + discount-first banner copy ([#10240](https://github.com/diegosouzapw/OmniRoute/pull/10240))
|
||||
- **feat(providers):** integrate audited free-tier gateways ([#9210](https://github.com/diegosouzapw/OmniRoute/pull/9210))
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
@@ -573,63 +553,6 @@ _Living section — regenerated 2026-08-12 from all cycle commits (cycle open `e
|
||||
- **fix(i18n) — direct pushes:** restore/unescape HTML entities in UI strings, translate capability-filter messages, complete web-session guide translations and Vietnamese parity
|
||||
- **fix(providers) — direct pushes:** repair the DeepAI registry import + executor
|
||||
- **fix(deps) — direct pushes:** CVE-driven bumps (nanoid, dompurify, mermaid, js-yaml + transitive deps for 26 Dependabot alerts) and retained isolated-build runtime dependencies in the pack
|
||||
- **fix(ci):** pin Build (advisory) to a hosted runner with memory provisioning ([#10408](https://github.com/diegosouzapw/OmniRoute/pull/10408))
|
||||
- **fix(providers):** refresh the translate-path golden for the bailian Token Plan endpoint ([#10410](https://github.com/diegosouzapw/OmniRoute/pull/10410))
|
||||
- **fix(sse):** surface Qwen/Alibaba personal Token Plan quota in dashboard and preflight ([#10290](https://github.com/diegosouzapw/OmniRoute/pull/10290))
|
||||
- **fix(deps):** pin next to an exact version so a fresh upstream release cannot break installs ([#10340](https://github.com/diegosouzapw/OmniRoute/pull/10340))
|
||||
- **fix(types):** restore custom model output limit contract ([#10339](https://github.com/diegosouzapw/OmniRoute/pull/10339)) — thanks @backryun
|
||||
- **fix(sse):** stop the executor-contract guard from hot-looping the router ([#10373](https://github.com/diegosouzapw/OmniRoute/pull/10373))
|
||||
- **fix(types):** validate nonstreaming JSON contracts ([#10258](https://github.com/diegosouzapw/OmniRoute/pull/10258)) — thanks @backryun
|
||||
- **fix(types):** narrow refresh token rotation inputs ([#10257](https://github.com/diegosouzapw/OmniRoute/pull/10257)) — thanks @backryun
|
||||
- **fix(types):** normalize executor result contracts ([#10256](https://github.com/diegosouzapw/OmniRoute/pull/10256)) — thanks @backryun
|
||||
- **fix(types):** align Responses stream options ([#10255](https://github.com/diegosouzapw/OmniRoute/pull/10255)) — thanks @backryun
|
||||
- **fix(types):** narrow combo credential preflight ([#10254](https://github.com/diegosouzapw/OmniRoute/pull/10254)) — thanks @backryun
|
||||
- **fix(compression):** cap countTextTokens at 50k chars and strip base64 data URIs ([#10118](https://github.com/diegosouzapw/OmniRoute/pull/10118)) — thanks @adevwithpurpose
|
||||
- **fix(ci):** clear base-reds on release/v3.8.50 (round 4) ([#10260](https://github.com/diegosouzapw/OmniRoute/pull/10260))
|
||||
- **fix(sse):** extract perplexity-web answers from workflow_block ([#10259](https://github.com/diegosouzapw/OmniRoute/pull/10259)) — thanks @jeyhunfaslanov
|
||||
- **fix(mcp):** persist and re-attach Gemini thoughtSignature on the direct Claude<->Gemini path ([#9448](https://github.com/diegosouzapw/OmniRoute/pull/9448)) — thanks @Sam280903
|
||||
- **fix(opencode-plugin):** respect log level for lifecycle output (#8982) ([#9316](https://github.com/diegosouzapw/OmniRoute/pull/9316)) — thanks @xiaoyaner0201
|
||||
- **fix(providers):** raise default provider probe timeout from 5s to 8s ([#9283](https://github.com/diegosouzapw/OmniRoute/pull/9283)) — thanks @Sam280903
|
||||
- **fix(opencode-plugin):** stop warning when an auto combo replaces its expected /v1/models twin (#8983) ([#9042](https://github.com/diegosouzapw/OmniRoute/pull/9042)) — thanks @xiaoyaner0201
|
||||
- **fix(opencode):** force CLI User-Agent when CLI identity synthesis is enabled ([#10222](https://github.com/diegosouzapw/OmniRoute/pull/10222)) — thanks @adevwithpurpose
|
||||
- **fix(deepseek-web):** classify business auth rejection as 401 ([#10218](https://github.com/diegosouzapw/OmniRoute/pull/10218)) — thanks @Zartharas
|
||||
- **fix(combo):** make failoverBeforeRetry actually skip the same-model retry ([#10217](https://github.com/diegosouzapw/OmniRoute/pull/10217)) — thanks @hartmark
|
||||
- **fix(responses):** preserve case-insensitive combo names before Codex rewrite ([#10177](https://github.com/diegosouzapw/OmniRoute/pull/10177)) — thanks @ddarkr
|
||||
- **fix(discovery):** parse reasoning tiers nested under metadata.reasoning.supported_efforts ([#10138](https://github.com/diegosouzapw/OmniRoute/pull/10138)) — thanks @excessivechaos
|
||||
- **fix(combo):** isolate session stickiness by combo ([#10137](https://github.com/diegosouzapw/OmniRoute/pull/10137)) — thanks @hydraxman
|
||||
- **fix(combo):** default chaos SSE to comment-only for OpenAI-compatible clients ([#10128](https://github.com/diegosouzapw/OmniRoute/pull/10128)) — thanks @herjarsa
|
||||
- **fix(kimi):** normalize MFJS tool schemas ([#10079](https://github.com/diegosouzapw/OmniRoute/pull/10079)) — thanks @xz-dev
|
||||
- **fix(mcp):** move pack validation out of unit suite ([#10065](https://github.com/diegosouzapw/OmniRoute/pull/10065)) — thanks @yansigit
|
||||
- **fix(zed-hosted):** send the provider wire values cloud.zed.dev accepts ([#10051](https://github.com/diegosouzapw/OmniRoute/pull/10051)) — thanks @ARC345
|
||||
- **fix(ci):** repair and wire the two live-server E2E suites ([#10050](https://github.com/diegosouzapw/OmniRoute/pull/10050)) — thanks @ARC345
|
||||
- **fix(reasoning):** preserve and replay assistant turns ([#10045](https://github.com/diegosouzapw/OmniRoute/pull/10045)) — thanks @jackjinke
|
||||
- **fix(types):** tighten chatCore helper contracts ([#10175](https://github.com/diegosouzapw/OmniRoute/pull/10175)) — thanks @backryun
|
||||
- **fix(cli):** read the full provider catalog instead of the 6-entry fallback ([#10097](https://github.com/diegosouzapw/OmniRoute/pull/10097)) — thanks @amartinawi
|
||||
- **fix(cli):** stop swallowing non-2xx responses into benign-looking results ([#10092](https://github.com/diegosouzapw/OmniRoute/pull/10092)) — thanks @amartinawi
|
||||
- **fix(cli):** openapi endpoints/paths/validate accept the served catalog shape ([#10091](https://github.com/diegosouzapw/OmniRoute/pull/10091)) — thanks @amartinawi
|
||||
- **fix(cli):** doctor detects prebuilt better-sqlite3 binaries ([#10090](https://github.com/diegosouzapw/OmniRoute/pull/10090)) — thanks @amartinawi
|
||||
- **fix(providers):** kilo-gateway authType should be optional, not apikey ([#10086](https://github.com/diegosouzapw/OmniRoute/pull/10086)) — thanks @TengSivtean
|
||||
- **fix(cli):** strip inline comments when parsing .env values ([#10101](https://github.com/diegosouzapw/OmniRoute/pull/10101)) — thanks @amartinawi
|
||||
- **fix(logging):** document CHAT_LOG_MAX_BODY_KB, capture messageCount for Responses API bodies ([#10038](https://github.com/diegosouzapw/OmniRoute/pull/10038)) — thanks @hartmark
|
||||
- **fix(dashboard):** expose OpenAI Responses store toggle for non-Codex connections ([#10121](https://github.com/diegosouzapw/OmniRoute/pull/10121)) — thanks @hartmark
|
||||
- **fix(combo):** clear LKGP pin when its target fails, not only set it on success ([#10034](https://github.com/diegosouzapw/OmniRoute/pull/10034)) — thanks @hartmark
|
||||
- **fix(sse):** provider-response summary format bugs (dashboard Provider Response panel) ([#10037](https://github.com/diegosouzapw/OmniRoute/pull/10037)) — thanks @hartmark
|
||||
- **fix(responses-api):** tool call after reasoning collided on the same output_index ([#10025](https://github.com/diegosouzapw/OmniRoute/pull/10025)) — thanks @hartmark
|
||||
- **fix(responses-api):** explicit function-tool declaration must win over apply_patch-is-custom fallback ([#10041](https://github.com/diegosouzapw/OmniRoute/pull/10041)) — thanks @hartmark
|
||||
- **fix(kimi):** recupera limite temporario sem bloquear conta ([#10058](https://github.com/diegosouzapw/OmniRoute/pull/10058)) — thanks @bortolidiego
|
||||
- **fix(translator):** preserve Responses custom tools for OpenAI-compatible providers ([#10114](https://github.com/diegosouzapw/OmniRoute/pull/10114)) — thanks @mtb-ninja
|
||||
- **fix(providers):** xai-oauth chat→responses body + missing breaker import (#10165) ([#10170](https://github.com/diegosouzapw/OmniRoute/pull/10170)) — thanks @nordz0r
|
||||
- **fix(ollama-cloud):** map xhigh reasoning effort to max ([#10160](https://github.com/diegosouzapw/OmniRoute/pull/10160)) — thanks @Chewji9875
|
||||
- **fix(translator):** strip Codex encrypted tool-schema key for Gemini/Antigravity ([#10053](https://github.com/diegosouzapw/OmniRoute/pull/10053)) — thanks @XDayonline
|
||||
- **fix(combo):** preserve OpenCode Free oc/ prefix for connections ([#10180](https://github.com/diegosouzapw/OmniRoute/pull/10180)) — thanks @AStupidBear
|
||||
- **fix(sse):** apply free-tier filter to auto/best-free on chat path ([#10199](https://github.com/diegosouzapw/OmniRoute/pull/10199)) — thanks @ggdayup
|
||||
- **fix(providers):** default missing cache_control.ttl to 1h on the native Claude OAuth path ([#10221](https://github.com/diegosouzapw/OmniRoute/pull/10221)) — thanks @jeff-alves
|
||||
- **fix(ci):** clear base-reds on release/v3.8.50 (round 3) ([#10213](https://github.com/diegosouzapw/OmniRoute/pull/10213))
|
||||
- **fix(security):** correct XML double-unescape and non-CSPRNG nonce from CodeQL sweep ([#10154](https://github.com/diegosouzapw/OmniRoute/pull/10154))
|
||||
- **fix(docker):** eliminate npm-bundled CVEs from the published image ([#10182](https://github.com/diegosouzapw/OmniRoute/pull/10182))
|
||||
- **fix(security):** resolve open CodeQL alerts ([#10188](https://github.com/diegosouzapw/OmniRoute/pull/10188))
|
||||
- **fix(dashboard):** retarget Kimi promo CTA to the API platform aff link ([#10200](https://github.com/diegosouzapw/OmniRoute/pull/10200))
|
||||
- **fix(build):** repair broken production build, red lint gate and SWR crash ([#10198](https://github.com/diegosouzapw/OmniRoute/pull/10198))
|
||||
|
||||
### 📝 Maintenance
|
||||
|
||||
@@ -775,178 +698,160 @@ _Living section — regenerated 2026-08-12 from all cycle commits (cycle open `e
|
||||
- **deps (rollup):** dependency bumps and lockfile maintenance across the cycle — Dependabot groups and manual CVE-driven bumps ([#9081](https://github.com/diegosouzapw/OmniRoute/pull/9081), [#9082](https://github.com/diegosouzapw/OmniRoute/pull/9082), [#9427](https://github.com/diegosouzapw/OmniRoute/pull/9427), [#9458](https://github.com/diegosouzapw/OmniRoute/pull/9458), [#9459](https://github.com/diegosouzapw/OmniRoute/pull/9459), [#9461](https://github.com/diegosouzapw/OmniRoute/pull/9461), [#9462](https://github.com/diegosouzapw/OmniRoute/pull/9462), [#9472](https://github.com/diegosouzapw/OmniRoute/pull/9472))
|
||||
- **docs/chore (rollup):** documentation, refactoring and repository-hygiene upkeep across the cycle ([#8954](https://github.com/diegosouzapw/OmniRoute/pull/8954), [#8991](https://github.com/diegosouzapw/OmniRoute/pull/8991), [#9059](https://github.com/diegosouzapw/OmniRoute/pull/9059), [#9194](https://github.com/diegosouzapw/OmniRoute/pull/9194), [#9258](https://github.com/diegosouzapw/OmniRoute/pull/9258), [#9508](https://github.com/diegosouzapw/OmniRoute/pull/9508))
|
||||
- **main-branch plumbing (rollup):** work that landed on `main` between cycles and was carried into this one — the Mergify merge-queue migration and tuning (#7168, #7179, #7216, #7220, #7225), npm-publish unblock via dynamic runner + CI build reuse (#8941), CodeQL-driven e2e mock hardening (#7559), hermetic self-ref guard (#6634, #7341), coverage-baseline tightening (#7347), Dependabot alert resolutions via npm overrides (#8067, #8070), README flag/doc-link polish (#8317), and the v3.8.49 release plumbing itself (#7076)
|
||||
- **deps:** bump the development group across 1 directory with 22 updates ([#10043](https://github.com/diegosouzapw/OmniRoute/pull/10043)) — thanks @app/dependabot
|
||||
- **deps:** bump electron from 43.2.0 to 43.3.0 in /electron ([#10042](https://github.com/diegosouzapw/OmniRoute/pull/10042)) — thanks @app/dependabot
|
||||
- **maint(release):** 45 direct pushes to the release branch with no PR ref — base-red and quality-gate repairs, i18n string completion and stream/type fixes (quality ×6, i18n ×5, deps ×3, agentrouter ×3, providers ×2, release ×2, security ×2, logging ×2)
|
||||
- **maint(repo):** 29 chore/ci/test/docs commits rolled up — quality baselines, mutation registration, CI re-triggers, doc restructure and repo hygiene (#10187, #10189, #10190, #10193, #10196, #10203, #10204, #10205, #10207, #10210, #10236, #10318)
|
||||
|
||||
### 🙌 Contributors
|
||||
|
||||
Thanks to everyone whose work landed in v3.8.50:
|
||||
|
||||
| Contributor | PRs / Issues |
|
||||
| ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [@AbdullahFageeh](https://github.com/AbdullahFageeh) | #9087 |
|
||||
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222 |
|
||||
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
|
||||
| [@agisota](https://github.com/agisota) | #9837 |
|
||||
| [@AgnesRiber](https://github.com/AgnesRiber) | #9718, #9976 |
|
||||
| [@ahmet-cetinkaya](https://github.com/ahmet-cetinkaya) | #8878 |
|
||||
| [@AIB1TAL0S](https://github.com/AIB1TAL0S) | #9284 |
|
||||
| [@AlanSyue](https://github.com/AlanSyue) | direct commit / report |
|
||||
| [@alex-jordan547](https://github.com/alex-jordan547) | #9235, #9245, #9813 |
|
||||
| [@amartinawi](https://github.com/amartinawi) | #10090, #10091, #10092, #10097, #10101 |
|
||||
| [@AndrianBalanescu](https://github.com/AndrianBalanescu) | #8888, #8889, #8890, #8891, #8892, #8893, #8894, #8895 |
|
||||
| [@AnhLead](https://github.com/AnhLead) | #9722 |
|
||||
| [@aniketshukla1](https://github.com/aniketshukla1) | #9148 |
|
||||
| [@Anjielon](https://github.com/Anjielon) | #8776 |
|
||||
| [@apoapostolov](https://github.com/apoapostolov) | #8916 |
|
||||
| [@ARC345](https://github.com/ARC345) | #9628, #10050, #10051 |
|
||||
| [@artickc](https://github.com/artickc) | #8571, #8578, #8791, #8843, #8870, #8927, #8974, #9097, #9549 |
|
||||
| [@Arul-](https://github.com/Arul-) | #9761 |
|
||||
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
|
||||
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
|
||||
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10178, #10175, #10254, #10255, #10256, #10257, #10258, #10339 |
|
||||
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
|
||||
| [@benzntech](https://github.com/benzntech) | #9810, #9812, #9939 |
|
||||
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
|
||||
| [@bortolidiego](https://github.com/bortolidiego) | #10058 |
|
||||
| [@branben](https://github.com/branben) | #9940 |
|
||||
| [@Chewji9875](https://github.com/Chewji9875) | #9257, #9420, #9821, #9994, #10160 |
|
||||
| [@chirag127](https://github.com/chirag127) | #6674 |
|
||||
| [@chloeassistant](https://github.com/chloeassistant) | #9675, #9746 |
|
||||
| [@configurowebmax](https://github.com/configurowebmax) | #8877 |
|
||||
| [@corefusiion](https://github.com/corefusiion) | #8285 |
|
||||
| [@costaeder](https://github.com/costaeder) | #8626, #8629, #8630 |
|
||||
| [@csoftware-arigpt](https://github.com/csoftware-arigpt) | #3440 |
|
||||
| [@DaDecky](https://github.com/DaDecky) | direct commit / report |
|
||||
| [@DarkEsteves](https://github.com/DarkEsteves) | #10250 |
|
||||
| [@ddarkr](https://github.com/ddarkr) | #9035, #9036, #10177 |
|
||||
| [@diegosouzapw](https://github.com/diegosouzapw) | maintainer |
|
||||
| [@Dingding-leo](https://github.com/Dingding-leo) | #7987, #8640, #8678, #8704, #8774, #8790, #8808, #8817 |
|
||||
| [@DinonowDev](https://github.com/DinonowDev) | #8804 |
|
||||
| [@Dragost](https://github.com/Dragost) | #8339 |
|
||||
| [@dsitmilis](https://github.com/dsitmilis) | direct commit / report |
|
||||
| [@Egorich-print](https://github.com/Egorich-print) | #9001, #9020, #9058 |
|
||||
| [@engmarcosjr](https://github.com/engmarcosjr) | #9993 |
|
||||
| [@epsilonode](https://github.com/epsilonode) | #8871 |
|
||||
| [@ervareza](https://github.com/ervareza) | direct commit / report |
|
||||
| [@excessivechaos](https://github.com/excessivechaos) | #10062, #10138 |
|
||||
| [@fajarhide](https://github.com/fajarhide) | #9191, #9198 |
|
||||
| [@fenix007](https://github.com/fenix007) | #9618 |
|
||||
| [@Gecky2102](https://github.com/Gecky2102) | #9280 |
|
||||
| [@ggdayup](https://github.com/ggdayup) | #10199 |
|
||||
| [@Gioxaa](https://github.com/Gioxaa) | #9162, #9171 |
|
||||
| [@HaoNgo232](https://github.com/HaoNgo232) | direct commit / report |
|
||||
| [@Hariprajwal](https://github.com/Hariprajwal) | #9922 |
|
||||
| [@hartmark](https://github.com/hartmark) | #9635, #9704, #9711, #9712, #9727, #9734, #9735, #9738, #9741, #9744, #9745, #9822, #10025, #10034, #10037, #10038, #10041, #10121, #10217 |
|
||||
| [@Hdiaktoros](https://github.com/Hdiaktoros) | #8930 |
|
||||
| [@HectorBernstorff](https://github.com/HectorBernstorff) | direct commit / report |
|
||||
| [@HellFiveOsborn](https://github.com/HellFiveOsborn) | #9248 |
|
||||
| [@herjarsa](https://github.com/herjarsa) | #9714, #9816, #9937, #9946, #10128 |
|
||||
| [@horacecar](https://github.com/horacecar) | #7679 |
|
||||
| [@HouMinXi](https://github.com/HouMinXi) | #8886, #8904, #8905, #8976, #8984, #9079, #9106, #9207, #9242, #9328, #9340, #9342, #9351, #9365, #9380, #9381, #9392, #9449, #9482, #9483, #9509, #9510, #9572, #9631, #9634, #9695, #9929 |
|
||||
| [@hppsc1215](https://github.com/hppsc1215) | #8970 |
|
||||
| [@hydraxman](https://github.com/hydraxman) | #10137 |
|
||||
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
|
||||
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
|
||||
| [@infinit-X](https://github.com/infinit-X) | #9095 |
|
||||
| [@isaaclb98](https://github.com/isaaclb98) | #9730 |
|
||||
| [@jackjinke](https://github.com/jackjinke) | #9556, #9601, #10005, #10045 |
|
||||
| [@jax-novita](https://github.com/jax-novita) | #8913 |
|
||||
| [@jeff-alves](https://github.com/jeff-alves) | #10221 |
|
||||
| [@jeyhunfaslanov](https://github.com/jeyhunfaslanov) | #10259 |
|
||||
| [@jhordanjw123](https://github.com/jhordanjw123) | #8736 |
|
||||
| [@jktan0504](https://github.com/jktan0504) | #9025 |
|
||||
| [@joachimBrindeau](https://github.com/joachimBrindeau) | #9200 |
|
||||
| [@JoshimOfficial](https://github.com/JoshimOfficial) | #9011 |
|
||||
| [@jowimila](https://github.com/jowimila) | #9325 |
|
||||
| [@JxnLexn](https://github.com/JxnLexn) | #8933, #8940, #8944, #8949 |
|
||||
| [@Kaedo17](https://github.com/Kaedo17) | #8922 |
|
||||
| [@khoazero123](https://github.com/khoazero123) | #9272 |
|
||||
| [@KittisakT](https://github.com/KittisakT) | #9423 |
|
||||
| [@KooshaPari](https://github.com/KooshaPari) | #7329 |
|
||||
| [@larin-vas](https://github.com/larin-vas) | #9828 |
|
||||
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
|
||||
| [@LeonG606](https://github.com/LeonG606) | #9457 |
|
||||
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
|
||||
| [@lucasalx](https://github.com/lucasalx) | #9919 |
|
||||
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
|
||||
| [@lukiod](https://github.com/lukiod) | #8828 |
|
||||
| [@luoyide](https://github.com/luoyide) | direct commit / report |
|
||||
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
|
||||
| [@maisdesign](https://github.com/maisdesign) | #8858 |
|
||||
| [@marchlhw](https://github.com/marchlhw) | #9050 |
|
||||
| [@matiasbaglieri](https://github.com/matiasbaglieri) | #9707 |
|
||||
| [@maxmad64bis](https://github.com/maxmad64bis) | #9150, #9246, #9291, #9414 |
|
||||
| [@McLuck](https://github.com/McLuck) | #8914 |
|
||||
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
|
||||
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244 |
|
||||
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
|
||||
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
|
||||
| [@Momen4444](https://github.com/Momen4444) | #9612 |
|
||||
| [@MrShitFox](https://github.com/MrShitFox) | #9826 |
|
||||
| [@mtb-ninja](https://github.com/mtb-ninja) | #10114 |
|
||||
| [@MumuTW](https://github.com/MumuTW) | #8839 |
|
||||
| [@mvanhorn](https://github.com/mvanhorn) | #9542 |
|
||||
| [@Mynacol](https://github.com/Mynacol) | #9733 |
|
||||
| [@nguyenha935](https://github.com/nguyenha935) | #9044, #9215 |
|
||||
| [@nordz0r](https://github.com/nordz0r) | #10170 |
|
||||
| [@nosolosoft](https://github.com/nosolosoft) | #8900 |
|
||||
| [@oyi77](https://github.com/oyi77) | #8299, #8752, #9158, #9818 |
|
||||
| [@pacocartones](https://github.com/pacocartones) | #10216 |
|
||||
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
|
||||
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
|
||||
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467 |
|
||||
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
|
||||
| [@qianze0628](https://github.com/qianze0628) | #9038 |
|
||||
| [@raflyazf](https://github.com/raflyazf) | direct commit / report |
|
||||
| [@Rahulsharma0810](https://github.com/Rahulsharma0810) | #8961 |
|
||||
| [@rinseaid](https://github.com/rinseaid) | #8945, #9037, #9932, #9933, #9969, #9982 |
|
||||
| [@rixzkiye](https://github.com/rixzkiye) | direct commit / report |
|
||||
| [@RobertsXML](https://github.com/RobertsXML) | direct commit / report |
|
||||
| [@royanrosyad85](https://github.com/royanrosyad85) | direct commit / report |
|
||||
| [@rushsinging](https://github.com/rushsinging) | #8947 |
|
||||
| [@ryan-brosas](https://github.com/ryan-brosas) | #9693 |
|
||||
| [@ryanngit](https://github.com/ryanngit) | direct commit / report |
|
||||
| [@sadSanta-07](https://github.com/sadSanta-07) | #9938 |
|
||||
| [@SalyyS1](https://github.com/SalyyS1) | direct commit / report |
|
||||
| [@Sam280903](https://github.com/Sam280903) | #9274, #9278, #9281, #9283, #9448 |
|
||||
| [@seakleangnhak](https://github.com/seakleangnhak) | direct commit / report |
|
||||
| [@seanford](https://github.com/seanford) | #8523 |
|
||||
| [@SemonCat](https://github.com/SemonCat) | direct commit / report |
|
||||
| [@shixi-li](https://github.com/shixi-li) | #9022, #9513, #10001 |
|
||||
| [@soulhakr](https://github.com/soulhakr) | #8799 |
|
||||
| [@stanleytejakusuma](https://github.com/stanleytejakusuma) | #9610 |
|
||||
| [@Stazyu](https://github.com/Stazyu) | #9007, #9226, #9438 |
|
||||
| [@SupremeNexas](https://github.com/SupremeNexas) | #9913 |
|
||||
| [@swingtempo](https://github.com/swingtempo) | #9307 |
|
||||
| [@szzhoujiarui](https://github.com/szzhoujiarui) | #9218 |
|
||||
| [@tald26](https://github.com/tald26) | #9959 |
|
||||
| [@taltas](https://github.com/taltas) | direct commit / report |
|
||||
| [@TechNickAI](https://github.com/TechNickAI) | #9251 |
|
||||
| [@TengSivtean](https://github.com/TengSivtean) | #10000, #10002, #10086 |
|
||||
| [@TheFrenchGhosty](https://github.com/TheFrenchGhosty) | #9326 |
|
||||
| [@tiangao88](https://github.com/tiangao88) | #10046 |
|
||||
| [@tuxmonteiro](https://github.com/tuxmonteiro) | #9065 |
|
||||
| [@vinogradovnet](https://github.com/vinogradovnet) | #9581 |
|
||||
| [@VXNCXNX](https://github.com/VXNCXNX) | #9111, #9783 |
|
||||
| [@wgordon17](https://github.com/wgordon17) | #8909, #9233, #9441, #9619 |
|
||||
| [@Witroch4](https://github.com/Witroch4) | #8713 |
|
||||
| [@witt3rd](https://github.com/witt3rd) | #9962, #9963 |
|
||||
| [@XDayonline](https://github.com/XDayonline) | #10053 |
|
||||
| [@xiaoyaner0201](https://github.com/xiaoyaner0201) | #8757, #8869, #8876, #8883, #8906, #8931, #9021, #9027, #9452, #9042, #9316 |
|
||||
| [@xz-dev](https://github.com/xz-dev) | #8908, #9199, #9205, #9262, #9290, #9313, #9555, #9569, #9629, #9788, #9983, #10079, #10243 |
|
||||
| [@yansigit](https://github.com/yansigit) | #9834, #9911, #9917, #9921, #10065 |
|
||||
| [@yidecode](https://github.com/yidecode) | direct commit / report |
|
||||
| [@yulinlina](https://github.com/yulinlina) | #10013 |
|
||||
| [@yutuknown](https://github.com/yutuknown) | #8999 |
|
||||
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
|
||||
| [@Zartharas](https://github.com/Zartharas) | #9161, #9164, #9181, #9182, #9184, #9185, #9186, #9189, #9294, #9825, #9833, #9936, #9965, #9992, #10218 |
|
||||
| [@Zenlyte](https://github.com/Zenlyte) | #9005 |
|
||||
| [@zhiru](https://github.com/zhiru) | #9099, #9101 |
|
||||
| [@ziuus](https://github.com/ziuus) | #8912 |
|
||||
| [@zuckdorsey](https://github.com/zuckdorsey) | #9723 |
|
||||
| Contributor | PRs / Issues |
|
||||
| --- | --- |
|
||||
| [@AbdullahFageeh](https://github.com/AbdullahFageeh) | #9087 |
|
||||
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790 |
|
||||
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
|
||||
| [@agisota](https://github.com/agisota) | #9837 |
|
||||
| [@AgnesRiber](https://github.com/AgnesRiber) | #9718, #9976 |
|
||||
| [@ahmet-cetinkaya](https://github.com/ahmet-cetinkaya) | #8878 |
|
||||
| [@AIB1TAL0S](https://github.com/AIB1TAL0S) | #9284 |
|
||||
| [@AlanSyue](https://github.com/AlanSyue) | direct commit / report |
|
||||
| [@alex-jordan547](https://github.com/alex-jordan547) | #9235, #9245, #9813 |
|
||||
| [@AndrianBalanescu](https://github.com/AndrianBalanescu) | #8888, #8889, #8890, #8891, #8892, #8893, #8894, #8895 |
|
||||
| [@AnhLead](https://github.com/AnhLead) | #9722 |
|
||||
| [@aniketshukla1](https://github.com/aniketshukla1) | #9148 |
|
||||
| [@Anjielon](https://github.com/Anjielon) | #8776 |
|
||||
| [@apoapostolov](https://github.com/apoapostolov) | #8916 |
|
||||
| [@ARC345](https://github.com/ARC345) | #9628 |
|
||||
| [@artickc](https://github.com/artickc) | #8571, #8578, #8791, #8843, #8870, #8927, #8974, #9097, #9549 |
|
||||
| [@Arul-](https://github.com/Arul-) | #9761 |
|
||||
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
|
||||
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10178 |
|
||||
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
|
||||
| [@benzntech](https://github.com/benzntech) | #9810, #9812, #9939 |
|
||||
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
|
||||
| [@branben](https://github.com/branben) | #9940 |
|
||||
| [@Chewji9875](https://github.com/Chewji9875) | #9257, #9420, #9821, #9994 |
|
||||
| [@chirag127](https://github.com/chirag127) | #6674 |
|
||||
| [@chloeassistant](https://github.com/chloeassistant) | #9675, #9746 |
|
||||
| [@configurowebmax](https://github.com/configurowebmax) | #8877 |
|
||||
| [@corefusiion](https://github.com/corefusiion) | #8285 |
|
||||
| [@costaeder](https://github.com/costaeder) | #8626, #8629, #8630 |
|
||||
| [@csoftware-arigpt](https://github.com/csoftware-arigpt) | #3440 |
|
||||
| [@DaDecky](https://github.com/DaDecky) | direct commit / report |
|
||||
| [@ddarkr](https://github.com/ddarkr) | #9035, #9036 |
|
||||
| [@Dingding-leo](https://github.com/Dingding-leo) | #7987, #8640, #8678, #8704, #8774, #8790, #8808, #8817 |
|
||||
| [@DinonowDev](https://github.com/DinonowDev) | #8804 |
|
||||
| [@Dragost](https://github.com/Dragost) | #8339 |
|
||||
| [@dsitmilis](https://github.com/dsitmilis) | direct commit / report |
|
||||
| [@Egorich-print](https://github.com/Egorich-print) | #9001, #9020, #9058 |
|
||||
| [@engmarcosjr](https://github.com/engmarcosjr) | #9993 |
|
||||
| [@epsilonode](https://github.com/epsilonode) | #8871 |
|
||||
| [@ervareza](https://github.com/ervareza) | direct commit / report |
|
||||
| [@fajarhide](https://github.com/fajarhide) | #9191, #9198 |
|
||||
| [@fenix007](https://github.com/fenix007) | #9618 |
|
||||
| [@Gecky2102](https://github.com/Gecky2102) | #9280 |
|
||||
| [@Gioxaa](https://github.com/Gioxaa) | #9162, #9171 |
|
||||
| [@HaoNgo232](https://github.com/HaoNgo232) | direct commit / report |
|
||||
| [@Hariprajwal](https://github.com/Hariprajwal) | #9922 |
|
||||
| [@hartmark](https://github.com/hartmark) | #9635, #9704, #9711, #9712, #9727, #9734, #9735, #9738, #9741, #9744, #9745, #9822 |
|
||||
| [@Hdiaktoros](https://github.com/Hdiaktoros) | #8930 |
|
||||
| [@HectorBernstorff](https://github.com/HectorBernstorff) | direct commit / report |
|
||||
| [@HellFiveOsborn](https://github.com/HellFiveOsborn) | #9248 |
|
||||
| [@herjarsa](https://github.com/herjarsa) | #9714, #9816, #9937, #9946 |
|
||||
| [@horacecar](https://github.com/horacecar) | #7679 |
|
||||
| [@HouMinXi](https://github.com/HouMinXi) | #8886, #8904, #8905, #8976, #8984, #9079, #9106, #9207, #9242, #9328, #9340, #9342, #9351, #9365, #9380, #9381, #9392, #9449, #9482, #9483, #9509, #9510, #9572, #9631, #9634, #9695, #9929 |
|
||||
| [@hppsc1215](https://github.com/hppsc1215) | #8970 |
|
||||
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
|
||||
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
|
||||
| [@infinit-X](https://github.com/infinit-X) | #9095 |
|
||||
| [@isaaclb98](https://github.com/isaaclb98) | #9730 |
|
||||
| [@jackjinke](https://github.com/jackjinke) | #9556, #9601, #10005 |
|
||||
| [@jax-novita](https://github.com/jax-novita) | #8913 |
|
||||
| [@jhordanjw123](https://github.com/jhordanjw123) | #8736 |
|
||||
| [@jktan0504](https://github.com/jktan0504) | #9025 |
|
||||
| [@joachimBrindeau](https://github.com/joachimBrindeau) | #9200 |
|
||||
| [@JoshimOfficial](https://github.com/JoshimOfficial) | #9011 |
|
||||
| [@jowimila](https://github.com/jowimila) | #9325 |
|
||||
| [@JxnLexn](https://github.com/JxnLexn) | #8933, #8940, #8944, #8949 |
|
||||
| [@Kaedo17](https://github.com/Kaedo17) | #8922 |
|
||||
| [@khoazero123](https://github.com/khoazero123) | #9272 |
|
||||
| [@KittisakT](https://github.com/KittisakT) | #9423 |
|
||||
| [@KooshaPari](https://github.com/KooshaPari) | #7329 |
|
||||
| [@larin-vas](https://github.com/larin-vas) | #9828 |
|
||||
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
|
||||
| [@LeonG606](https://github.com/LeonG606) | #9457 |
|
||||
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
|
||||
| [@lucasalx](https://github.com/lucasalx) | #9919 |
|
||||
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
|
||||
| [@lukiod](https://github.com/lukiod) | #8828 |
|
||||
| [@luoyide](https://github.com/luoyide) | direct commit / report |
|
||||
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
|
||||
| [@maisdesign](https://github.com/maisdesign) | #8858 |
|
||||
| [@marchlhw](https://github.com/marchlhw) | #9050 |
|
||||
| [@matiasbaglieri](https://github.com/matiasbaglieri) | #9707 |
|
||||
| [@maxmad64bis](https://github.com/maxmad64bis) | #9150, #9246, #9291, #9414 |
|
||||
| [@McLuck](https://github.com/McLuck) | #8914 |
|
||||
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
|
||||
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244 |
|
||||
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
|
||||
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
|
||||
| [@Momen4444](https://github.com/Momen4444) | #9612 |
|
||||
| [@MrShitFox](https://github.com/MrShitFox) | #9826 |
|
||||
| [@MumuTW](https://github.com/MumuTW) | #8839 |
|
||||
| [@mvanhorn](https://github.com/mvanhorn) | #9542 |
|
||||
| [@Mynacol](https://github.com/Mynacol) | #9733 |
|
||||
| [@nguyenha935](https://github.com/nguyenha935) | #9044, #9215 |
|
||||
| [@nosolosoft](https://github.com/nosolosoft) | #8900 |
|
||||
| [@oyi77](https://github.com/oyi77) | #8299, #8752, #9158, #9818 |
|
||||
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
|
||||
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
|
||||
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467 |
|
||||
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
|
||||
| [@qianze0628](https://github.com/qianze0628) | #9038 |
|
||||
| [@raflyazf](https://github.com/raflyazf) | direct commit / report |
|
||||
| [@Rahulsharma0810](https://github.com/Rahulsharma0810) | #8961 |
|
||||
| [@rinseaid](https://github.com/rinseaid) | #8945, #9037, #9932, #9933, #9969, #9982 |
|
||||
| [@rixzkiye](https://github.com/rixzkiye) | direct commit / report |
|
||||
| [@RobertsXML](https://github.com/RobertsXML) | direct commit / report |
|
||||
| [@royanrosyad85](https://github.com/royanrosyad85) | direct commit / report |
|
||||
| [@rushsinging](https://github.com/rushsinging) | #8947 |
|
||||
| [@ryan-brosas](https://github.com/ryan-brosas) | #9693 |
|
||||
| [@ryanngit](https://github.com/ryanngit) | direct commit / report |
|
||||
| [@sadSanta-07](https://github.com/sadSanta-07) | #9938 |
|
||||
| [@SalyyS1](https://github.com/SalyyS1) | direct commit / report |
|
||||
| [@Sam280903](https://github.com/Sam280903) | #9274, #9278, #9281 |
|
||||
| [@seakleangnhak](https://github.com/seakleangnhak) | direct commit / report |
|
||||
| [@seanford](https://github.com/seanford) | #8523 |
|
||||
| [@SemonCat](https://github.com/SemonCat) | direct commit / report |
|
||||
| [@shixi-li](https://github.com/shixi-li) | #9022, #9513, #10001 |
|
||||
| [@soulhakr](https://github.com/soulhakr) | #8799 |
|
||||
| [@stanleytejakusuma](https://github.com/stanleytejakusuma) | #9610 |
|
||||
| [@Stazyu](https://github.com/Stazyu) | #9007, #9226, #9438 |
|
||||
| [@SupremeNexas](https://github.com/SupremeNexas) | #9913 |
|
||||
| [@swingtempo](https://github.com/swingtempo) | #9307 |
|
||||
| [@szzhoujiarui](https://github.com/szzhoujiarui) | #9218 |
|
||||
| [@tald26](https://github.com/tald26) | #9959 |
|
||||
| [@taltas](https://github.com/taltas) | direct commit / report |
|
||||
| [@TechNickAI](https://github.com/TechNickAI) | #9251 |
|
||||
| [@TengSivtean](https://github.com/TengSivtean) | #10000, #10002 |
|
||||
| [@TheFrenchGhosty](https://github.com/TheFrenchGhosty) | #9326 |
|
||||
| [@tuxmonteiro](https://github.com/tuxmonteiro) | #9065 |
|
||||
| [@vinogradovnet](https://github.com/vinogradovnet) | #9581 |
|
||||
| [@VXNCXNX](https://github.com/VXNCXNX) | #9111, #9783 |
|
||||
| [@wgordon17](https://github.com/wgordon17) | #8909, #9233, #9441, #9619 |
|
||||
| [@Witroch4](https://github.com/Witroch4) | #8713 |
|
||||
| [@witt3rd](https://github.com/witt3rd) | #9962, #9963 |
|
||||
| [@xiaoyaner0201](https://github.com/xiaoyaner0201) | #8757, #8869, #8876, #8883, #8906, #8931, #9021, #9027, #9452 |
|
||||
| [@xz-dev](https://github.com/xz-dev) | #8908, #9199, #9205, #9262, #9290, #9313, #9555, #9569, #9629, #9788, #9983 |
|
||||
| [@yansigit](https://github.com/yansigit) | #9834, #9911, #9917, #9921 |
|
||||
| [@yidecode](https://github.com/yidecode) | direct commit / report |
|
||||
| [@yulinlina](https://github.com/yulinlina) | #10013 |
|
||||
| [@yutuknown](https://github.com/yutuknown) | #8999 |
|
||||
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
|
||||
| [@Zartharas](https://github.com/Zartharas) | #9161, #9164, #9181, #9182, #9184, #9185, #9186, #9189, #9294, #9825, #9833, #9936, #9965, #9992 |
|
||||
| [@Zenlyte](https://github.com/Zenlyte) | #9005 |
|
||||
| [@zhiru](https://github.com/zhiru) | #9099, #9101 |
|
||||
| [@ziuus](https://github.com/ziuus) | #8912 |
|
||||
| [@zuckdorsey](https://github.com/zuckdorsey) | #9723 |
|
||||
| [@diegosouzapw](https://github.com/diegosouzapw) | maintainer |
|
||||
|
||||
---
|
||||
|
||||
@@ -1243,7 +1148,6 @@ _Living section — regenerated 2026-07-19 from all 306 cycle commits (bump 2c62
|
||||
- **feat(quality):** temporary relax of complexity/file-size ratchets for v3.8.50-3.8.54 PREPARE phase ([#8767](https://github.com/diegosouzapw/OmniRoute/pull/8767))
|
||||
- **feat(db):** let the migration runner scan extra namespaced directories ([#8770](https://github.com/diegosouzapw/OmniRoute/pull/8770))
|
||||
- **feat(api):** prompt-cache health summary endpoint and analytics tab ([#8827](https://github.com/diegosouzapw/OmniRoute/pull/8827))
|
||||
|
||||
### ⚡ Performance
|
||||
|
||||
- **perf(db):** project columns + composite index in getProviderConnections ([#6918](https://github.com/diegosouzapw/OmniRoute/pull/6918)) — thanks @oyi77
|
||||
@@ -1259,7 +1163,6 @@ _Living section — regenerated 2026-07-19 from all 306 cycle commits (bump 2c62
|
||||
- **perf:** lazy provider init, P2C quota cache, structuredClone elimination, getSettings→getCachedSettings (batch 2) ([#7893](https://github.com/diegosouzapw/OmniRoute/pull/7893)) — thanks @oyi77
|
||||
- **perf(api):** singleflight version lookups ([#8301](https://github.com/diegosouzapw/OmniRoute/pull/8301)) — thanks @RaviTharuma
|
||||
- **perf(api):** skip the full catalog build for quota-exclusive keys ([#8771](https://github.com/diegosouzapw/OmniRoute/pull/8771))
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **fix:** add re-entrancy guard to token health check sweep ([#6917](https://github.com/diegosouzapw/OmniRoute/pull/6917)) — thanks @oyi77
|
||||
@@ -1659,7 +1562,7 @@ _Living section — regenerated 2026-07-19 from all 306 cycle commits (bump 2c62
|
||||
- **fix(resilience):** a combo step "pinned" to one fingerprint account (mimocode/mcode/opencode multi-account providers) never actually resolved to that account, so it couldn't fail over when the pinned account was depleted ([#6696](https://github.com/diegosouzapw/OmniRoute/issues/6696), relates #6612) — the combo builder UI encodes an account pin as a composite connectionId (`${rowId}|fp|${fingerprint}`, `src/lib/combos/builderOptions.ts`), but `expandTargetsByFingerprints()` (`open-sse/services/combo/fingerprintExpansion.ts`) looked that composite string up directly in `connectionById` (keyed by real DB row ids), got `undefined`, and passed the target through unchanged, still carrying the bogus composite id — so downstream credential resolution could never match it either. `expandTargetsByFingerprints()` now splits the `|fp|` composite id back into the real connection row id + the pinned fingerprint (new `splitFingerprintPin()` helper) before any lookup, resolving the target to the real connectionId (with the pinned fingerprint carried on the new `pinnedFingerprint` field) instead of the inert composite string. Regression guard: `tests/unit/combo-fingerprint-pin-6696.test.ts`. ([#6732](https://github.com/diegosouzapw/OmniRoute/pull/6732))
|
||||
- **fix(api):** Responses passthrough emitted event-only SSE frames (no `data:` line) for every dropped commentary event, breaking the OpenAI Python SDK's `sse.json()` parser ([#6561](https://github.com/diegosouzapw/OmniRoute/issues/6561)), follow-up to #6199/#6232 — the commentary-drop `continue;` branches in `open-sse/utils/stream.ts` skipped the `data:` line for a dropped commentary event but never cleared the already-buffered `event:` line for that same frame, so the next blank line flushed the stale `event:` line alone. Both drop sites now call `clearPendingPassthroughEvent()` before `continue`, discarding the buffered prefix along with the dropped payload; the commentary-drop decision itself was extracted into a new `open-sse/utils/responsesCommentaryDrop.ts` so the fix does not grow the frozen `stream.ts`. Regression guard: `tests/unit/responses-commentary-event-frame-6561.test.ts` (realistic `event:\ndata:\n\n` frames — the existing #6199 test only used bare `data:` lines and never exercised this path). ([#6735](https://github.com/diegosouzapw/OmniRoute/pull/6735))
|
||||
- **fix(compression):** `/api/compression/preview`'s top-level `originalTokens`/`compressedTokens` diverged from `engineBreakdown[0]`'s counts for the same single-engine run (tiktoken outer counts vs the `JSON.stringify(...).length/4` estimate per engine), worst on small inputs. A new `reconcileSingleEngineTokens()` overwrites the single-engine breakdown entry with the outer, more accurate figures; multi-step pipeline breakdowns are left untouched ([#6488](https://github.com/diegosouzapw/OmniRoute/issues/6488)). Regression guard: `tests/unit/compression/preview-outer-engine-token-reconcile-6488.test.ts`. ([#6741](https://github.com/diegosouzapw/OmniRoute/pull/6741))
|
||||
- **fix(resilience):** account selection could pick an account already out of quota upstream on every credentialed route except `chat`/`codex` ([#6686](https://github.com/diegosouzapw/OmniRoute/issues/6686)) — `getProviderCredentials()` (`src/sse/services/auth.ts`) only skips a connection when a _local cache_ already flags it exhausted (`isQuotaExhaustedForRequest`/`src/domain/quotaCache.ts`); it never itself calls the registered upstream `QuotaFetcher`. Only `getProviderCredentialsWithQuotaPreflight()` performs that live upstream check, and it was wired into exactly 2 call sites (`src/sse/handlers/chat.ts`, `src/app/api/internal/codex-responses-ws/route.ts`) — every other credentialed route (`rerank`, `images/generations`, `images/edits`, `audio/transcriptions|speech|translations`, `videos/generations`, `music/generations`, `ocr`, `providers/[provider]/embeddings`, `providers/[provider]/images/generations`, `web/fetch`, `moderations`, `search`) called the plain, cache-only selector, so an account whose cache entry was never populated (e.g. its first request landed on one of these routes) could be selected even at 0% quota remaining. Those 14 call sites now go through `getProviderCredentialsWithQuotaPreflight()` instead, matching chat/codex coverage. Regression guard: `tests/unit/issue-6686-quota-preflight-coverage.test.ts` (static check that none of the routes call the plain selector anymore + a behavioral check that the preflight-aware selector blocks a 100%-used account). ([#6742](https://github.com/diegosouzapw/OmniRoute/pull/6742))
|
||||
- **fix(resilience):** account selection could pick an account already out of quota upstream on every credentialed route except `chat`/`codex` ([#6686](https://github.com/diegosouzapw/OmniRoute/issues/6686)) — `getProviderCredentials()` (`src/sse/services/auth.ts`) only skips a connection when a *local cache* already flags it exhausted (`isQuotaExhaustedForRequest`/`src/domain/quotaCache.ts`); it never itself calls the registered upstream `QuotaFetcher`. Only `getProviderCredentialsWithQuotaPreflight()` performs that live upstream check, and it was wired into exactly 2 call sites (`src/sse/handlers/chat.ts`, `src/app/api/internal/codex-responses-ws/route.ts`) — every other credentialed route (`rerank`, `images/generations`, `images/edits`, `audio/transcriptions|speech|translations`, `videos/generations`, `music/generations`, `ocr`, `providers/[provider]/embeddings`, `providers/[provider]/images/generations`, `web/fetch`, `moderations`, `search`) called the plain, cache-only selector, so an account whose cache entry was never populated (e.g. its first request landed on one of these routes) could be selected even at 0% quota remaining. Those 14 call sites now go through `getProviderCredentialsWithQuotaPreflight()` instead, matching chat/codex coverage. Regression guard: `tests/unit/issue-6686-quota-preflight-coverage.test.ts` (static check that none of the routes call the plain selector anymore + a behavioral check that the preflight-aware selector blocks a 100%-used account). ([#6742](https://github.com/diegosouzapw/OmniRoute/pull/6742))
|
||||
- **fix(api):** `reasoning_content` (extended-thinking text) was silently dropped from `/v1/chat/completions` SSE on the `claude-web` and `v0-vercel-web` executors ([#6662](https://github.com/diegosouzapw/OmniRoute/issues/6662)) — every chunk builder in both adapters hardcoded `delta: { content: ... }` with no reasoning path, unlike the established pattern already used by `default.ts`/`deepseek-web.ts`/`bedrock.ts` and the real-Anthropic-API `claude-to-openai.ts` translator (`thinking_delta` → `reasoning_content`). `v0-vercel-web.ts` now forwards an upstream `delta.reasoning_content` field (streaming and non-streaming) the same way `deepseek-web.ts` does. `claude-web.ts`'s `buildClaudeStreamingResponse` now maps a `content_block_start`(`type: "thinking"`)/`content_block_delta`(`delta.thinking`) pair onto `delta.reasoning_content`, and `claude-web/payload.ts`'s `transformToClaude()` no longer hardcodes `thinking_mode: "off"` — a new `wantsExtendedThinking()` derives it from the request's `reasoning_effort`/`reasoning.effort`/`thinking.type` signal, so extended thinking can actually be requested. Regression guard: `tests/unit/issue-6662-repro.test.ts` (RED→GREEN for both adapters). ([#6743](https://github.com/diegosouzapw/OmniRoute/pull/6743))
|
||||
- **fix(api):** the compression config PUT schema now accepts `enableRenderers` for the RTK engine instead of rejecting the documented option (#6703, #6757 — thanks @alltomatos, with an independent duplicate fix from @chirag127 via #6756).
|
||||
- **fix(api):** raised the provider `apiKey` length cap for cookie-based web providers, whose session-cookie credentials legitimately exceed the previous limit (#6715, #6759 — thanks @alltomatos).
|
||||
@@ -1779,7 +1682,7 @@ _Living section — regenerated 2026-07-19 from all 306 cycle commits (bump 2c62
|
||||
- fix(sse): stop stream readiness from treating a choices-less mid-stream error frame as a successful stream, so combo can fail over instead of returning zero `choices` (#7503)
|
||||
- Fixed the Codex connection **Test** button always reporting success for ChatGPT-account tokens: the probe used `gpt-5.3-codex`, a codex-only model ChatGPT accounts reject with a 400 — the same status the probe treats as "auth OK", so a bad token was indistinguishable from a good one. It now probes with `gpt-5.5`, a model ChatGPT-account sessions actually support (#7521).
|
||||
- The Codex account import (`POST /api/oauth/codex/import`) now validates each record's `refresh_token` against OpenAI's OAuth endpoint before persisting the connection: an already-invalidated session (`refresh_token_invalidated` / a dead `auth.json`) is rejected with a clear "run `codex login` again and re-import" message instead of importing as `active` and failing confusingly on first use. Valid tokens import as before, with any rotated tokens applied (#7522).
|
||||
- The PKCE OAuth start (`/api/oauth/[provider]/start-callback-server`, used by Codex/Windsurf/Devin) now detects when OmniRoute is being driven from a remote host and returns a reverse-tunnel hint (`remoteHost`, `tunnelCommand`, `message`) instead of hanging silently: the callback server binds the _server's_ localhost:PORT, so a browser on a different machine would redirect to its own localhost and never complete. Loopback access is unchanged (#7523).
|
||||
- The PKCE OAuth start (`/api/oauth/[provider]/start-callback-server`, used by Codex/Windsurf/Devin) now detects when OmniRoute is being driven from a remote host and returns a reverse-tunnel hint (`remoteHost`, `tunnelCommand`, `message`) instead of hanging silently: the callback server binds the *server's* localhost:PORT, so a browser on a different machine would redirect to its own localhost and never complete. Loopback access is unchanged (#7523).
|
||||
- fix(providers): search providers now expose a static model catalog derived from `searchTypes`, fixing "does not support models listing" 400 for serper-search, brave-search, perplexity-search, exa-search, tavily-search, google-pse-search, youcom-search, searxng-search, zai-search (#7529)
|
||||
- fix(sse): map `tool_search` to a Chat function tool instead of dropping it during Responses->Chat translation (#7532)
|
||||
- fix(sse): gate `verbosity`/`prompt_cache_key` on OpenAI destination during Responses->Chat translation, stopping the leak to non-OpenAI upstreams like NVIDIA (#7533)
|
||||
@@ -2089,7 +1992,6 @@ _Living section — regenerated 2026-07-19 from all 306 cycle commits (bump 2c62
|
||||
- **fix(dashboard):** the /home quick-start cards no longer prefetch — #8292 opted the sidebar out of automatic route prefetch but left the landing page's own five links untouched, so first paint still fired 12 speculative RSC requests. The e2e guard shipped in that same PR could not catch it: it hung in the auth helper and never reached its assertion until this release's CI.
|
||||
- **fix(dashboard):** Request Logs detail no longer crashes on a structured error object — #7920 introduced `formatErrorForDisplay` for exactly this, but the combo-503 / cooldown checks added by #8213 read the raw field and called `.toLowerCase()` on it. Both paths now share the helper.
|
||||
- **fix(dashboard):** the logs detail modal stops reopening on first close again — #6830 fixed it by reading the deep-link id once, and the #8354 page rewrite regressed it by reading the live `searchParams` on every render, flipping the prop mid-session.
|
||||
|
||||
### 📚 Docs
|
||||
|
||||
- **docs(quality):** codify retry policy per runner + release-level drift rule (WS5.4/WS5.5) ([#7107](https://github.com/diegosouzapw/OmniRoute/pull/7107))
|
||||
@@ -2132,7 +2034,6 @@ _Living section — regenerated 2026-07-19 from all 306 cycle commits (bump 2c62
|
||||
- **docs(codex):** document session affinity and stream idle for long tasks ([#8709](https://github.com/diegosouzapw/OmniRoute/pull/8709)) — thanks @DinonowDev
|
||||
- **docs:** replace outdated Polish docs with translation from latest English ([#8823](https://github.com/diegosouzapw/OmniRoute/pull/8823)) — thanks @leszek3737
|
||||
- **docs:** restore the Polish API_REFERENCE removed by #8823 ([#8831](https://github.com/diegosouzapw/OmniRoute/pull/8831))
|
||||
|
||||
### 🧪 Tests & Quality
|
||||
|
||||
- **test(build):** derive pack-artifact closures for all npm-shipped entrypoints (#7065 class) ([#7081](https://github.com/diegosouzapw/OmniRoute/pull/7081))
|
||||
@@ -2150,7 +2051,6 @@ _Living section — regenerated 2026-07-19 from all 306 cycle commits (bump 2c62
|
||||
- **test(e2e):** contract test for the full provider journey ([#8444](https://github.com/diegosouzapw/OmniRoute/pull/8444)) — thanks @HoneyTyagii
|
||||
- **test(sse):** repair two base-red gates on release/v3.8.49 ([#8490](https://github.com/diegosouzapw/OmniRoute/pull/8490)) — thanks @backryun
|
||||
- **test(context):** isolate context-manager suite from local DATA_DIR ([#8596](https://github.com/diegosouzapw/OmniRoute/pull/8596)) — thanks @DinonowDev
|
||||
|
||||
### 🔧 Chores / CI
|
||||
|
||||
- **chore(release):** gate the sync-back push on release-green --quick (WS0.3) ([#7083](https://github.com/diegosouzapw/OmniRoute/pull/7083))
|
||||
@@ -2241,7 +2141,6 @@ _Living section — regenerated 2026-07-19 from all 306 cycle commits (bump 2c62
|
||||
- **refactor(sse):** use the shared ApiKeyMetadata in reasoningRouting instead of a local duck-type ([#8643](https://github.com/diegosouzapw/OmniRoute/pull/8643)) — thanks @backryun
|
||||
- **refactor(sse):** narrow three media-generation result unions ([#8645](https://github.com/diegosouzapw/OmniRoute/pull/8645)) — thanks @backryun
|
||||
- **refactor(sse):** declare the semantic-cache read path's parameters ([#8646](https://github.com/diegosouzapw/OmniRoute/pull/8646)) — thanks @backryun
|
||||
|
||||
### 🔀 Other
|
||||
|
||||
- [needs-vps] fix(electron): materialize Turbopack hashed-module symlinks during packaging (#6724, #6594) ([#6794](https://github.com/diegosouzapw/OmniRoute/pull/6794)) — thanks @huohua-dev
|
||||
@@ -2271,7 +2170,6 @@ _Living section — regenerated 2026-07-19 from all 306 cycle commits (bump 2c62
|
||||
- **refactor(antigravity):** align official clients and callable catalog ([#8013](https://github.com/diegosouzapw/OmniRoute/pull/8013)) — thanks @backryun
|
||||
- **refactor(compression):** extract resolveHeadroomDetail to keep dispatchCompression under the complexity gate ([#8058](https://github.com/diegosouzapw/OmniRoute/pull/8058))
|
||||
- **deps:** bump next from 16.2.10 to 16.2.11 ([#8235](https://github.com/diegosouzapw/OmniRoute/pull/8235)) — thanks @dependabot[bot]
|
||||
|
||||
### 🩹 Direct release-branch fixes (no PR — authorized base-red sweep, 2026-07-18)
|
||||
|
||||
- **fix(base-red):** full-suite realignment after the 102-PR merge campaign: two real production fixes (legacy `refresh_token` column healed before its index is created; `shouldSkipCloudSyncInitialization` no longer swaps its `(env, argv)` arguments) plus 13 test files, goldens, provider counts, and env docs realigned to the live-validated behavior of the merged PRs.
|
||||
@@ -2279,7 +2177,6 @@ _Living section — regenerated 2026-07-19 from all 306 cycle commits (bump 2c62
|
||||
- **test(ui):** the `vitest:ui` suite was red across the whole cycle and nobody saw it — the job kept being cancelled by successive pushes, so a blocking gate never ran to completion. Root cause: #7935 instrumented ~180 shared/dashboard components with `next-intl` without updating the tests that mount them. Fixed at the shared setup (`tests/_setup/vitestUiPolyfills.ts`) with a translator backed by the real `en.json`, memoized per namespace so components whose `useCallback`/`useEffect` depend on `t` no longer loop; 15 test files realigned to the real strings. 194→198 files green.
|
||||
|
||||
### 📝 Maintenance
|
||||
|
||||
- **Merge-train script** (`scripts/release/merge-train.sh`): batch-validates N queued PRs as ONE merged result on the runner box — merges every queued PR into a throwaway worktree cut from the release tip, runs the fast-gates parity suite once, and prints the `--admin` evidence block per PR (merge-gates §7). Replaces O(N²) per-PR CI re-runs in merge-storms. Regression guard: `tests/unit/merge-train-plan.test.ts`. ([#6784](https://github.com/diegosouzapw/OmniRoute/pull/6784))
|
||||
- **release:** `list-uncovered-commits.mjs` now unions the CHANGELOG scan window with `changelog.d/` fragment refs (filename `<PR>-` prefix + every `#N` in the body), so a commit covered only by a fragment is no longer reported as an uncovered reconciliation gap ([#6857](https://github.com/diegosouzapw/OmniRoute/issues/6857) via [#6878](https://github.com/diegosouzapw/OmniRoute/pull/6878))
|
||||
- **chore(ci):** stop dependabot from proposing `typescript` majors — `typescript-eslint` pins a hard peer upper bound (`>=4.8.4 <6.1.0`), so a TS 7 bump violates the peer and takes the whole toolchain red at once. #7068 grouped it with 6 harmless dev bumps and blocked all of them. TS majors now migrate intentionally, in their own PR.
|
||||
@@ -2377,190 +2274,195 @@ _Living section — regenerated 2026-07-19 from all 306 cycle commits (bump 2c62
|
||||
- **CI**: promote `test:vitest:ui` to a blocking gate — the suite is 870/870 green again after the WS6.1 triage (#7127), so `continue-on-error` is removed from the vitest job
|
||||
- chore(tests): fix all 70 failing `test:vitest:ui` tests across 30 files (was advisory/parked) — root causes were 15 node:test-authored `.tsx` files never collected by vitest, a missing `window.matchMedia` jsdom polyfill, stale assertions against a redesigned BuildTab wizard / CompressionHub Phase-2 UI, and one obsolete test for a retired Plans screen; suite is now 158/158 files, 870/870 tests green (promotion to blocking is a follow-up)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 🙌 Contributors
|
||||
|
||||
Thanks to everyone whose work landed in v3.8.49:
|
||||
|
||||
| Contributor | PRs / Issues |
|
||||
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [@0x2f0](https://github.com/0x2f0) | #8679 |
|
||||
| [@0xheycat](https://github.com/0xheycat) | #8751 |
|
||||
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #8123 |
|
||||
| [@adrianaryaputra](https://github.com/adrianaryaputra) | #7928 |
|
||||
| [@advane204f](https://github.com/advane204f) | direct commit / report |
|
||||
| [@Ajeesh25353646](https://github.com/Ajeesh25353646) | #7528 |
|
||||
| [@allanvb](https://github.com/allanvb) | #8471, #8759, #8814, #8862 |
|
||||
| [@alltomatos](https://github.com/alltomatos) | #6703, #6715, #6756, #6757, #6759, #6813, #6819, #6821, #7041, #7042, #7164, #7277, #7490, #7492, #7644 |
|
||||
| [@alvaretto](https://github.com/alvaretto) | #8077, #8161, #8170 |
|
||||
| [@amitgolan60-coder](https://github.com/amitgolan60-coder) | #8727 |
|
||||
| [@andrea-kingautomation](https://github.com/andrea-kingautomation) | #7678 |
|
||||
| [@andrewmunsell](https://github.com/andrewmunsell) | #6774, #6779, #6795 |
|
||||
| [@AndrianBalanescu](https://github.com/AndrianBalanescu) | #6828, #6829, #7794, #7804, #7810, #7813, #7816, #7891, #8050 |
|
||||
| [@anhdiepmmk](https://github.com/anhdiepmmk) | direct commit / report |
|
||||
| [@anndev-69](https://github.com/anndev-69) | direct commit / report |
|
||||
| [@apoapostolov](https://github.com/apoapostolov) | #8127 |
|
||||
| [@arpit-jaiswal-dev](https://github.com/arpit-jaiswal-dev) | #7881 |
|
||||
| [@artickc](https://github.com/artickc) | #6763, #6955, #7204, #7696, #7768, #7896, #7900, #7911, #7930, #7994, #8006, #8159, #8470, #8496, #8511, #8863 |
|
||||
| [@Arul-](https://github.com/Arul-) | #7878 |
|
||||
| [@asynx6](https://github.com/asynx6) | direct commit / report |
|
||||
| [@attid](https://github.com/attid) | #6984 |
|
||||
| [@backryun](https://github.com/backryun) | #6280, #6675, #6862, #7296, #7314, #7358, #7531, #7687, #7772, #7812, #7866, #7874, #7882, #7914, #8013, #8225, #8226, #8227, #8230, #8266, #8275, #8298, #8464, #8473, #8483, #8485, #8489, #8490, #8498, #8499, #8520, #8525, #8528, #8531, #8533, #8557, #8638, #8639, #8641, #8643, #8644, #8645, #8646, #8647, #8661, #8663, #8665, #8732, #8810, #8811, #8812, #8815, #8816, #8819, #8820, #8824 |
|
||||
| [@beingshafin](https://github.com/beingshafin) | direct commit / report |
|
||||
| [@brick30llc-ctrl](https://github.com/brick30llc-ctrl) | #6944 |
|
||||
| [@brunnolouzada](https://github.com/brunnolouzada) | #8581 |
|
||||
| [@c4usal](https://github.com/c4usal) | #7627, #8129 |
|
||||
| [@CahyokPutraDev99](https://github.com/CahyokPutraDev99) | direct commit / report |
|
||||
| [@Capslockb](https://github.com/Capslockb) | #7892 |
|
||||
| [@CarmeloCampos](https://github.com/CarmeloCampos) | direct commit / report |
|
||||
| [@Chewji9875](https://github.com/Chewji9875) | #7545 |
|
||||
| [@chirag127](https://github.com/chirag127) | #6022, #6593, #6643, #6644, #6646, #6650, #6769, #6771, #6804, #7079, #7520, #8143 |
|
||||
| [@chitholian](https://github.com/chitholian) | direct commit / report |
|
||||
| [@chy1211](https://github.com/chy1211) | direct commit / report |
|
||||
| [@CitrusIce](https://github.com/CitrusIce) | #6937, #6938 |
|
||||
| [@costaeder](https://github.com/costaeder) | #8628 |
|
||||
| [@Dan-ex-hub](https://github.com/Dan-ex-hub) | #7743 |
|
||||
| [@danscMax](https://github.com/danscMax) | #7359, #7511, #7517, #7648, #7656, #7672, #7689 |
|
||||
| [@dependabot](https://github.com/dependabot) | #7897, #7898, #8235 |
|
||||
| [@Dingding-leo](https://github.com/Dingding-leo) | #7988, #7989, #8162, #8165, #8167, #8283, #8286, #8287, #8633, #8636, #8642, #8651, #8652, #8667, #8691, #8715, #8730, #8731, #8762, #8763, #8764, #8795 |
|
||||
| [@DinonowDev](https://github.com/DinonowDev) | #8552, #8559, #8583, #8596, #8615, #8709, #8710, #8716, #8798, #8800, #8802 |
|
||||
| [@dionisius95](https://github.com/dionisius95) | direct commit / report |
|
||||
| [@DKotsyuba](https://github.com/DKotsyuba) | #7500 |
|
||||
| [@dongwook-chan](https://github.com/dongwook-chan) | #7574, #7582, #7704 |
|
||||
| [@Dragost](https://github.com/Dragost) | #8289 |
|
||||
| [@Duongkhanhtool](https://github.com/Duongkhanhtool) | direct commit / report |
|
||||
| [@dvirarad](https://github.com/dvirarad) | #8410 |
|
||||
| [@ekinnee](https://github.com/ekinnee) | #7601, #7613, #7614, #7662, #7779, #7927, #7932, #7980, #8735 |
|
||||
| [@enjoyer-hub](https://github.com/enjoyer-hub) | #6647, #7863 |
|
||||
| [@epsilonode](https://github.com/epsilonode) | #8724 |
|
||||
| [@evinjohnn](https://github.com/evinjohnn) | direct commit / report |
|
||||
| [@fajarbossit](https://github.com/fajarbossit) | direct commit / report |
|
||||
| [@felipeleite](https://github.com/felipeleite) | direct commit / report |
|
||||
| [@fenix007](https://github.com/fenix007) | #7171, #7399, #8306, #8561 |
|
||||
| [@FenjuFu](https://github.com/FenjuFu) | #7942 |
|
||||
| [@floze-the-genius](https://github.com/floze-the-genius) | #7707 |
|
||||
| [@fontvu](https://github.com/fontvu) | direct commit / report |
|
||||
| [@fuko2935](https://github.com/fuko2935) | #8726 |
|
||||
| [@fzrilsh](https://github.com/fzrilsh) | direct commit / report |
|
||||
| [@gitcommit90](https://github.com/gitcommit90) | #6986 |
|
||||
| [@glazec](https://github.com/glazec) | #8632 |
|
||||
| [@growab](https://github.com/growab) | #7062, #7300 |
|
||||
| [@guanbear](https://github.com/guanbear) | #7028 |
|
||||
| [@guhcostan](https://github.com/guhcostan) | #8433 |
|
||||
| [@hartmark](https://github.com/hartmark) | #8208, #8209, #8210, #8211, #8212, #8213, #8337, #8341, #8354, #8462 |
|
||||
| [@HassiyYT](https://github.com/HassiyYT) | #7864 |
|
||||
| [@heishen6](https://github.com/heishen6) | direct commit / report |
|
||||
| [@herjarsa](https://github.com/herjarsa) | #7612, #7625, #7633, #7869, #7871, #8476 |
|
||||
| [@HoneyTyagii](https://github.com/HoneyTyagii) | #8444 |
|
||||
| [@HouMinXi](https://github.com/HouMinXi) | #7035, #7129, #7290, #7398, #7408, #7973, #8290, #8312, #8842, #8845, #8860, #8865 |
|
||||
| [@hppsc1215](https://github.com/hppsc1215) | #7546, #8835 |
|
||||
| [@huohua-dev](https://github.com/huohua-dev) | #6794 |
|
||||
| [@hydraxman](https://github.com/hydraxman) | #7909 |
|
||||
| [@iamraydoan](https://github.com/iamraydoan) | #6798 |
|
||||
| [@ianriizky](https://github.com/ianriizky) | #6072, #6538 |
|
||||
| [@ikelvingo](https://github.com/ikelvingo) | #8355 |
|
||||
| [@insoln](https://github.com/insoln) | #7906, #7908, #8041, #8054, #8062 |
|
||||
| [@irvandikky](https://github.com/irvandikky) | #7695 |
|
||||
| [@isiahw1](https://github.com/isiahw1) | #7555 |
|
||||
| [@itiwant](https://github.com/itiwant) | direct commit / report |
|
||||
| [@janeza2](https://github.com/janeza2) | #6308 |
|
||||
| [@Jordannst](https://github.com/Jordannst) | direct commit / report |
|
||||
| [@JoshimOfficial](https://github.com/JoshimOfficial) | #8526 |
|
||||
| [@justdoGIT](https://github.com/justdoGIT) | #8695 |
|
||||
| [@JxnLexn](https://github.com/JxnLexn) | #6776, #6993, #7154, #7177, #7269, #7273, #7280, #7281, #7282, #7323, #7360, #7377, #7378, #7379, #7380, #7381, #7419, #7607, #7894, #7905, #7912, #8008, #8009, #8010 |
|
||||
| [@kamenkadmitry](https://github.com/kamenkadmitry) | #7350, #7425 |
|
||||
| [@kaon0388v1](https://github.com/kaon0388v1) | #7049 |
|
||||
| [@KaynXu](https://github.com/KaynXu) | #8284 |
|
||||
| [@KooshaPari](https://github.com/KooshaPari) | #6611, #6632, #6856, #7008, #7087, #7093, #7128, #7130, #7136, #7315, #7318, #7334, #7336 |
|
||||
| [@KunN-21](https://github.com/KunN-21) | direct commit / report |
|
||||
| [@leninejunior](https://github.com/leninejunior) | #8049 |
|
||||
| [@leszek3737](https://github.com/leszek3737) | #7782, #7807, #8343, #8543, #8823 |
|
||||
| [@like3213934360-lab](https://github.com/like3213934360-lab) | direct commit / report |
|
||||
| [@linhdmn](https://github.com/linhdmn) | #8439 |
|
||||
| [@Long-Feeds](https://github.com/Long-Feeds) | #8011 |
|
||||
| [@loulanyue](https://github.com/loulanyue) | #7540 |
|
||||
| [@lucasjustinudin](https://github.com/lucasjustinudin) | direct commit / report |
|
||||
| [@lunkerchen](https://github.com/lunkerchen) | #8024 |
|
||||
| [@makcimbx](https://github.com/makcimbx) | #7692, #8171, #8432 |
|
||||
| [@Mananz90](https://github.com/Mananz90) | #8723 |
|
||||
| [@marceli1404](https://github.com/marceli1404) | #8570 |
|
||||
| [@maxmad64bis](https://github.com/maxmad64bis) | #8660 |
|
||||
| [@megamen32](https://github.com/megamen32) | #7313 |
|
||||
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8224 |
|
||||
| [@mikeiagents](https://github.com/mikeiagents) | #8598 |
|
||||
| [@MikeTuev](https://github.com/MikeTuev) | #6586 |
|
||||
| [@mikolaj92](https://github.com/mikolaj92) | #6973 |
|
||||
| [@MisileLab](https://github.com/MisileLab) | #8566 |
|
||||
| [@MonteNegroX](https://github.com/MonteNegroX) | #8217 |
|
||||
| [@Moseyuh333](https://github.com/Moseyuh333) | #7781, #8264 |
|
||||
| [@MrFadiAi](https://github.com/MrFadiAi) | #7073 |
|
||||
| [@mrprohack](https://github.com/mrprohack) | direct commit / report |
|
||||
| [@MumuTW](https://github.com/MumuTW) | #8423, #8425, #8426, #8427, #8428, #8524, #8534, #8544, #8545, #8546, #8547, #8548, #8554, #8582, #8585, #8589, #8592, #8604, #8605, #8612, #8619, #8657, #8690, #8741, #8749 |
|
||||
| [@mustafa-phd](https://github.com/mustafa-phd) | #7686 |
|
||||
| [@NBN-N3](https://github.com/NBN-N3) | #8794 |
|
||||
| [@nguyenha935](https://github.com/nguyenha935) | #7493, #7547, #7552, #7553, #7629, #7935, #8031, #8098, #8233, #8565 |
|
||||
| [@nguyenphi37](https://github.com/nguyenphi37) | direct commit / report |
|
||||
| [@not-knope](https://github.com/not-knope) | #8206 |
|
||||
| [@nramabad](https://github.com/nramabad) | #7926 |
|
||||
| [@oyi77](https://github.com/oyi77) | #6917, #6918, #6919, #6920, #6921, #6923, #7032, #7045, #7046, #7066, #7070, #7178, #7719, #7744, #7787, #7893, #8219 |
|
||||
| [@Pitchfork-and-Torch](https://github.com/Pitchfork-and-Torch) | #6747, #6791 |
|
||||
| [@professional-ALFIE](https://github.com/professional-ALFIE) | #6877 |
|
||||
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8032, #8220, #8250, #8309, #8441, #8467, #8488, #8493, #8494, #8495, #8586, #8587, #8606, #8607, #8608, #8611, #8805, #8806 |
|
||||
| [@QRcode1337](https://github.com/QRcode1337) | #7034 |
|
||||
| [@quanturbo](https://github.com/quanturbo) | #6780 |
|
||||
| [@rafaeldrincon](https://github.com/rafaeldrincon) | #8866, #8867 |
|
||||
| [@rafaumeu](https://github.com/rafaumeu) | #6813, #6979, #6982, #6983, #6987, #6988, #7001, #7808, #7815, #8071, #8113, #8179, #8184, #8185, #8190, #8195, #8196, #8203 |
|
||||
| [@RaviTharuma](https://github.com/RaviTharuma) | #7852, #7853, #7855, #7862, #7885, #7972, #7978, #8021, #8022, #8023, #8025, #8027, #8030, #8101, #8102, #8124, #8252, #8292, #8296, #8301, #8302, #8303, #8304, #8308 |
|
||||
| [@RCrushMe](https://github.com/RCrushMe) | #8151, #8378 |
|
||||
| [@ricatix](https://github.com/ricatix) | direct commit / report |
|
||||
| [@ridho9](https://github.com/ridho9) | #8310 |
|
||||
| [@rinseaid](https://github.com/rinseaid) | #8721, #8729, #8821 |
|
||||
| [@rixzkiye](https://github.com/rixzkiye) | direct commit / report |
|
||||
| [@rqzbeh](https://github.com/rqzbeh) | #8514, #8515 |
|
||||
| [@rushsinging](https://github.com/rushsinging) | #7256 |
|
||||
| [@ryanngit](https://github.com/ryanngit) | direct commit / report |
|
||||
| [@samir-abis](https://github.com/samir-abis) | direct commit / report |
|
||||
| [@seanford](https://github.com/seanford) | #8194, #8218, #8232 |
|
||||
| [@SeaXen](https://github.com/SeaXen) | #7063, #7264, #7294 |
|
||||
| [@Securiteru](https://github.com/Securiteru) | #7683 |
|
||||
| [@SemonCat](https://github.com/SemonCat) | direct commit / report |
|
||||
| [@shixi-li](https://github.com/shixi-li) | #8569 |
|
||||
| [@SingCJ](https://github.com/SingCJ) | direct commit / report |
|
||||
| [@skutanjir](https://github.com/skutanjir) | #7865, #7939 |
|
||||
| [@spacesky-cell](https://github.com/spacesky-cell) | direct commit / report |
|
||||
| [@SteeleHu](https://github.com/SteeleHu) | #8747 |
|
||||
| [@sumanxg](https://github.com/sumanxg) | #8837, #8856 |
|
||||
| [@swingtempo](https://github.com/swingtempo) | #7790, #8349, #8766 |
|
||||
| [@Tasogarre](https://github.com/Tasogarre) | #7861, #8207 |
|
||||
| [@techsolutionmta](https://github.com/techsolutionmta) | direct commit / report |
|
||||
| [@tenshiak](https://github.com/tenshiak) | #7274, #7643 |
|
||||
| [@terrafirmbot-source](https://github.com/terrafirmbot-source) | #8685 |
|
||||
| [@thepigdestroyer](https://github.com/thepigdestroyer) | #7497 |
|
||||
| [@tianrking](https://github.com/tianrking) | #7353 |
|
||||
| [@tientien17](https://github.com/tientien17) | #7841, #7844, #7925 |
|
||||
| [@TitoTFP](https://github.com/TitoTFP) | #8838 |
|
||||
| [@tjengbudi](https://github.com/tjengbudi) | #4009 |
|
||||
| [@tmone](https://github.com/tmone) | #7806, #7933 |
|
||||
| [@TrackCrewGalore](https://github.com/TrackCrewGalore) | #6271, #8128 |
|
||||
| [@trfi](https://github.com/trfi) | direct commit / report |
|
||||
| [@TuyulSpam](https://github.com/TuyulSpam) | direct commit / report |
|
||||
| [@ViFigueiredo](https://github.com/ViFigueiredo) | #7301 |
|
||||
| [@vzts](https://github.com/vzts) | #7390 |
|
||||
| [@warelik](https://github.com/warelik) | direct commit / report |
|
||||
| [@way-art](https://github.com/way-art) | direct commit / report |
|
||||
| [@webmasterarbez](https://github.com/webmasterarbez) | #7504 |
|
||||
| [@wgordon17](https://github.com/wgordon17) | #8852 |
|
||||
| [@whale9820](https://github.com/whale9820) | direct commit / report |
|
||||
| [@Wibias](https://github.com/Wibias) | #7125 |
|
||||
| [@wilsonicdev](https://github.com/wilsonicdev) | direct commit / report |
|
||||
| [@Witroch4](https://github.com/Witroch4) | #6753, #6762, #6790, #7901, #7902 |
|
||||
| [@XCrag](https://github.com/XCrag) | direct commit / report |
|
||||
| [@xiaoyaner0201](https://github.com/xiaoyaner0201) | #8122, #8261, #8262 |
|
||||
| [@xier2012](https://github.com/xier2012) | #7036, #7050, #7052, #7053, #7056, #7059, #7060, #7061, #7166, #7299 |
|
||||
| [@xxue-z](https://github.com/xxue-z) | #7098 |
|
||||
| [@xz-dev](https://github.com/xz-dev) | #6323, #6330, #6714, #6727, #7004, #7012, #7027, #7673, #7700, #7747, #7776, #7843 |
|
||||
| [@yidecode](https://github.com/yidecode) | direct commit / report |
|
||||
| [@yinaoxiong](https://github.com/yinaoxiong) | #6805 |
|
||||
| [@diegosouzapw](https://github.com/diegosouzapw) | maintainer |
|
||||
| Contributor | PRs / Issues |
|
||||
| --- | --- |
|
||||
| [@0x2f0](https://github.com/0x2f0) | #8679 |
|
||||
| [@0xheycat](https://github.com/0xheycat) | #8751 |
|
||||
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #8123 |
|
||||
| [@adrianaryaputra](https://github.com/adrianaryaputra) | #7928 |
|
||||
| [@advane204f](https://github.com/advane204f) | direct commit / report |
|
||||
| [@Ajeesh25353646](https://github.com/Ajeesh25353646) | #7528 |
|
||||
| [@allanvb](https://github.com/allanvb) | #8471, #8759, #8814, #8862 |
|
||||
| [@alltomatos](https://github.com/alltomatos) | #6703, #6715, #6756, #6757, #6759, #6813, #6819, #6821, #7041, #7042, #7164, #7277, #7490, #7492, #7644 |
|
||||
| [@alvaretto](https://github.com/alvaretto) | #8077, #8161, #8170 |
|
||||
| [@amitgolan60-coder](https://github.com/amitgolan60-coder) | #8727 |
|
||||
| [@andrea-kingautomation](https://github.com/andrea-kingautomation) | #7678 |
|
||||
| [@andrewmunsell](https://github.com/andrewmunsell) | #6774, #6779, #6795 |
|
||||
| [@AndrianBalanescu](https://github.com/AndrianBalanescu) | #6828, #6829, #7794, #7804, #7810, #7813, #7816, #7891, #8050 |
|
||||
| [@anhdiepmmk](https://github.com/anhdiepmmk) | direct commit / report |
|
||||
| [@anndev-69](https://github.com/anndev-69) | direct commit / report |
|
||||
| [@apoapostolov](https://github.com/apoapostolov) | #8127 |
|
||||
| [@arpit-jaiswal-dev](https://github.com/arpit-jaiswal-dev) | #7881 |
|
||||
| [@artickc](https://github.com/artickc) | #6763, #6955, #7204, #7696, #7768, #7896, #7900, #7911, #7930, #7994, #8006, #8159, #8470, #8496, #8511, #8863 |
|
||||
| [@Arul-](https://github.com/Arul-) | #7878 |
|
||||
| [@asynx6](https://github.com/asynx6) | direct commit / report |
|
||||
| [@attid](https://github.com/attid) | #6984 |
|
||||
| [@backryun](https://github.com/backryun) | #6280, #6675, #6862, #7296, #7314, #7358, #7531, #7687, #7772, #7812, #7866, #7874, #7882, #7914, #8013, #8225, #8226, #8227, #8230, #8266, #8275, #8298, #8464, #8473, #8483, #8485, #8489, #8490, #8498, #8499, #8520, #8525, #8528, #8531, #8533, #8557, #8638, #8639, #8641, #8643, #8644, #8645, #8646, #8647, #8661, #8663, #8665, #8732, #8810, #8811, #8812, #8815, #8816, #8819, #8820, #8824 |
|
||||
| [@beingshafin](https://github.com/beingshafin) | direct commit / report |
|
||||
| [@brick30llc-ctrl](https://github.com/brick30llc-ctrl) | #6944 |
|
||||
| [@brunnolouzada](https://github.com/brunnolouzada) | #8581 |
|
||||
| [@c4usal](https://github.com/c4usal) | #7627, #8129 |
|
||||
| [@CahyokPutraDev99](https://github.com/CahyokPutraDev99) | direct commit / report |
|
||||
| [@Capslockb](https://github.com/Capslockb) | #7892 |
|
||||
| [@CarmeloCampos](https://github.com/CarmeloCampos) | direct commit / report |
|
||||
| [@Chewji9875](https://github.com/Chewji9875) | #7545 |
|
||||
| [@chirag127](https://github.com/chirag127) | #6022, #6593, #6643, #6644, #6646, #6650, #6769, #6771, #6804, #7079, #7520, #8143 |
|
||||
| [@chitholian](https://github.com/chitholian) | direct commit / report |
|
||||
| [@chy1211](https://github.com/chy1211) | direct commit / report |
|
||||
| [@CitrusIce](https://github.com/CitrusIce) | #6937, #6938 |
|
||||
| [@costaeder](https://github.com/costaeder) | #8628 |
|
||||
| [@Dan-ex-hub](https://github.com/Dan-ex-hub) | #7743 |
|
||||
| [@danscMax](https://github.com/danscMax) | #7359, #7511, #7517, #7648, #7656, #7672, #7689 |
|
||||
| [@dependabot](https://github.com/dependabot) | #7897, #7898, #8235 |
|
||||
| [@Dingding-leo](https://github.com/Dingding-leo) | #7988, #7989, #8162, #8165, #8167, #8283, #8286, #8287, #8633, #8636, #8642, #8651, #8652, #8667, #8691, #8715, #8730, #8731, #8762, #8763, #8764, #8795 |
|
||||
| [@DinonowDev](https://github.com/DinonowDev) | #8552, #8559, #8583, #8596, #8615, #8709, #8710, #8716, #8798, #8800, #8802 |
|
||||
| [@dionisius95](https://github.com/dionisius95) | direct commit / report |
|
||||
| [@DKotsyuba](https://github.com/DKotsyuba) | #7500 |
|
||||
| [@dongwook-chan](https://github.com/dongwook-chan) | #7574, #7582, #7704 |
|
||||
| [@Dragost](https://github.com/Dragost) | #8289 |
|
||||
| [@Duongkhanhtool](https://github.com/Duongkhanhtool) | direct commit / report |
|
||||
| [@dvirarad](https://github.com/dvirarad) | #8410 |
|
||||
| [@ekinnee](https://github.com/ekinnee) | #7601, #7613, #7614, #7662, #7779, #7927, #7932, #7980, #8735 |
|
||||
| [@enjoyer-hub](https://github.com/enjoyer-hub) | #6647, #7863 |
|
||||
| [@epsilonode](https://github.com/epsilonode) | #8724 |
|
||||
| [@evinjohnn](https://github.com/evinjohnn) | direct commit / report |
|
||||
| [@fajarbossit](https://github.com/fajarbossit) | direct commit / report |
|
||||
| [@felipeleite](https://github.com/felipeleite) | direct commit / report |
|
||||
| [@fenix007](https://github.com/fenix007) | #7171, #7399, #8306, #8561 |
|
||||
| [@FenjuFu](https://github.com/FenjuFu) | #7942 |
|
||||
| [@floze-the-genius](https://github.com/floze-the-genius) | #7707 |
|
||||
| [@fontvu](https://github.com/fontvu) | direct commit / report |
|
||||
| [@fuko2935](https://github.com/fuko2935) | #8726 |
|
||||
| [@fzrilsh](https://github.com/fzrilsh) | direct commit / report |
|
||||
| [@gitcommit90](https://github.com/gitcommit90) | #6986 |
|
||||
| [@glazec](https://github.com/glazec) | #8632 |
|
||||
| [@growab](https://github.com/growab) | #7062, #7300 |
|
||||
| [@guanbear](https://github.com/guanbear) | #7028 |
|
||||
| [@guhcostan](https://github.com/guhcostan) | #8433 |
|
||||
| [@hartmark](https://github.com/hartmark) | #8208, #8209, #8210, #8211, #8212, #8213, #8337, #8341, #8354, #8462 |
|
||||
| [@HassiyYT](https://github.com/HassiyYT) | #7864 |
|
||||
| [@heishen6](https://github.com/heishen6) | direct commit / report |
|
||||
| [@herjarsa](https://github.com/herjarsa) | #7612, #7625, #7633, #7869, #7871, #8476 |
|
||||
| [@HoneyTyagii](https://github.com/HoneyTyagii) | #8444 |
|
||||
| [@HouMinXi](https://github.com/HouMinXi) | #7035, #7129, #7290, #7398, #7408, #7973, #8290, #8312, #8842, #8845, #8860, #8865 |
|
||||
| [@hppsc1215](https://github.com/hppsc1215) | #7546, #8835 |
|
||||
| [@huohua-dev](https://github.com/huohua-dev) | #6794 |
|
||||
| [@hydraxman](https://github.com/hydraxman) | #7909 |
|
||||
| [@iamraydoan](https://github.com/iamraydoan) | #6798 |
|
||||
| [@ianriizky](https://github.com/ianriizky) | #6072, #6538 |
|
||||
| [@ikelvingo](https://github.com/ikelvingo) | #8355 |
|
||||
| [@insoln](https://github.com/insoln) | #7906, #7908, #8041, #8054, #8062 |
|
||||
| [@irvandikky](https://github.com/irvandikky) | #7695 |
|
||||
| [@isiahw1](https://github.com/isiahw1) | #7555 |
|
||||
| [@itiwant](https://github.com/itiwant) | direct commit / report |
|
||||
| [@janeza2](https://github.com/janeza2) | #6308 |
|
||||
| [@Jordannst](https://github.com/Jordannst) | direct commit / report |
|
||||
| [@JoshimOfficial](https://github.com/JoshimOfficial) | #8526 |
|
||||
| [@justdoGIT](https://github.com/justdoGIT) | #8695 |
|
||||
| [@JxnLexn](https://github.com/JxnLexn) | #6776, #6993, #7154, #7177, #7269, #7273, #7280, #7281, #7282, #7323, #7360, #7377, #7378, #7379, #7380, #7381, #7419, #7607, #7894, #7905, #7912, #8008, #8009, #8010 |
|
||||
| [@kamenkadmitry](https://github.com/kamenkadmitry) | #7350, #7425 |
|
||||
| [@kaon0388v1](https://github.com/kaon0388v1) | #7049 |
|
||||
| [@KaynXu](https://github.com/KaynXu) | #8284 |
|
||||
| [@KooshaPari](https://github.com/KooshaPari) | #6611, #6632, #6856, #7008, #7087, #7093, #7128, #7130, #7136, #7315, #7318, #7334, #7336 |
|
||||
| [@KunN-21](https://github.com/KunN-21) | direct commit / report |
|
||||
| [@leninejunior](https://github.com/leninejunior) | #8049 |
|
||||
| [@leszek3737](https://github.com/leszek3737) | #7782, #7807, #8343, #8543, #8823 |
|
||||
| [@like3213934360-lab](https://github.com/like3213934360-lab) | direct commit / report |
|
||||
| [@linhdmn](https://github.com/linhdmn) | #8439 |
|
||||
| [@Long-Feeds](https://github.com/Long-Feeds) | #8011 |
|
||||
| [@loulanyue](https://github.com/loulanyue) | #7540 |
|
||||
| [@lucasjustinudin](https://github.com/lucasjustinudin) | direct commit / report |
|
||||
| [@lunkerchen](https://github.com/lunkerchen) | #8024 |
|
||||
| [@makcimbx](https://github.com/makcimbx) | #7692, #8171, #8432 |
|
||||
| [@Mananz90](https://github.com/Mananz90) | #8723 |
|
||||
| [@marceli1404](https://github.com/marceli1404) | #8570 |
|
||||
| [@maxmad64bis](https://github.com/maxmad64bis) | #8660 |
|
||||
| [@megamen32](https://github.com/megamen32) | #7313 |
|
||||
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8224 |
|
||||
| [@mikeiagents](https://github.com/mikeiagents) | #8598 |
|
||||
| [@MikeTuev](https://github.com/MikeTuev) | #6586 |
|
||||
| [@mikolaj92](https://github.com/mikolaj92) | #6973 |
|
||||
| [@MisileLab](https://github.com/MisileLab) | #8566 |
|
||||
| [@MonteNegroX](https://github.com/MonteNegroX) | #8217 |
|
||||
| [@Moseyuh333](https://github.com/Moseyuh333) | #7781, #8264 |
|
||||
| [@MrFadiAi](https://github.com/MrFadiAi) | #7073 |
|
||||
| [@mrprohack](https://github.com/mrprohack) | direct commit / report |
|
||||
| [@MumuTW](https://github.com/MumuTW) | #8423, #8425, #8426, #8427, #8428, #8524, #8534, #8544, #8545, #8546, #8547, #8548, #8554, #8582, #8585, #8589, #8592, #8604, #8605, #8612, #8619, #8657, #8690, #8741, #8749 |
|
||||
| [@mustafa-phd](https://github.com/mustafa-phd) | #7686 |
|
||||
| [@NBN-N3](https://github.com/NBN-N3) | #8794 |
|
||||
| [@nguyenha935](https://github.com/nguyenha935) | #7493, #7547, #7552, #7553, #7629, #7935, #8031, #8098, #8233, #8565 |
|
||||
| [@nguyenphi37](https://github.com/nguyenphi37) | direct commit / report |
|
||||
| [@not-knope](https://github.com/not-knope) | #8206 |
|
||||
| [@nramabad](https://github.com/nramabad) | #7926 |
|
||||
| [@oyi77](https://github.com/oyi77) | #6917, #6918, #6919, #6920, #6921, #6923, #7032, #7045, #7046, #7066, #7070, #7178, #7719, #7744, #7787, #7893, #8219 |
|
||||
| [@Pitchfork-and-Torch](https://github.com/Pitchfork-and-Torch) | #6747, #6791 |
|
||||
| [@professional-ALFIE](https://github.com/professional-ALFIE) | #6877 |
|
||||
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8032, #8220, #8250, #8309, #8441, #8467, #8488, #8493, #8494, #8495, #8586, #8587, #8606, #8607, #8608, #8611, #8805, #8806 |
|
||||
| [@QRcode1337](https://github.com/QRcode1337) | #7034 |
|
||||
| [@quanturbo](https://github.com/quanturbo) | #6780 |
|
||||
| [@rafaeldrincon](https://github.com/rafaeldrincon) | #8866, #8867 |
|
||||
| [@rafaumeu](https://github.com/rafaumeu) | #6813, #6979, #6982, #6983, #6987, #6988, #7001, #7808, #7815, #8071, #8113, #8179, #8184, #8185, #8190, #8195, #8196, #8203 |
|
||||
| [@RaviTharuma](https://github.com/RaviTharuma) | #7852, #7853, #7855, #7862, #7885, #7972, #7978, #8021, #8022, #8023, #8025, #8027, #8030, #8101, #8102, #8124, #8252, #8292, #8296, #8301, #8302, #8303, #8304, #8308 |
|
||||
| [@RCrushMe](https://github.com/RCrushMe) | #8151, #8378 |
|
||||
| [@ricatix](https://github.com/ricatix) | direct commit / report |
|
||||
| [@ridho9](https://github.com/ridho9) | #8310 |
|
||||
| [@rinseaid](https://github.com/rinseaid) | #8721, #8729, #8821 |
|
||||
| [@rixzkiye](https://github.com/rixzkiye) | direct commit / report |
|
||||
| [@rqzbeh](https://github.com/rqzbeh) | #8514, #8515 |
|
||||
| [@rushsinging](https://github.com/rushsinging) | #7256 |
|
||||
| [@ryanngit](https://github.com/ryanngit) | direct commit / report |
|
||||
| [@samir-abis](https://github.com/samir-abis) | direct commit / report |
|
||||
| [@seanford](https://github.com/seanford) | #8194, #8218, #8232 |
|
||||
| [@SeaXen](https://github.com/SeaXen) | #7063, #7264, #7294 |
|
||||
| [@Securiteru](https://github.com/Securiteru) | #7683 |
|
||||
| [@SemonCat](https://github.com/SemonCat) | direct commit / report |
|
||||
| [@shixi-li](https://github.com/shixi-li) | #8569 |
|
||||
| [@SingCJ](https://github.com/SingCJ) | direct commit / report |
|
||||
| [@skutanjir](https://github.com/skutanjir) | #7865, #7939 |
|
||||
| [@spacesky-cell](https://github.com/spacesky-cell) | direct commit / report |
|
||||
| [@SteeleHu](https://github.com/SteeleHu) | #8747 |
|
||||
| [@sumanxg](https://github.com/sumanxg) | #8837, #8856 |
|
||||
| [@swingtempo](https://github.com/swingtempo) | #7790, #8349, #8766 |
|
||||
| [@Tasogarre](https://github.com/Tasogarre) | #7861, #8207 |
|
||||
| [@techsolutionmta](https://github.com/techsolutionmta) | direct commit / report |
|
||||
| [@tenshiak](https://github.com/tenshiak) | #7274, #7643 |
|
||||
| [@terrafirmbot-source](https://github.com/terrafirmbot-source) | #8685 |
|
||||
| [@thepigdestroyer](https://github.com/thepigdestroyer) | #7497 |
|
||||
| [@tianrking](https://github.com/tianrking) | #7353 |
|
||||
| [@tientien17](https://github.com/tientien17) | #7841, #7844, #7925 |
|
||||
| [@TitoTFP](https://github.com/TitoTFP) | #8838 |
|
||||
| [@tjengbudi](https://github.com/tjengbudi) | #4009 |
|
||||
| [@tmone](https://github.com/tmone) | #7806, #7933 |
|
||||
| [@TrackCrewGalore](https://github.com/TrackCrewGalore) | #6271, #8128 |
|
||||
| [@trfi](https://github.com/trfi) | direct commit / report |
|
||||
| [@TuyulSpam](https://github.com/TuyulSpam) | direct commit / report |
|
||||
| [@ViFigueiredo](https://github.com/ViFigueiredo) | #7301 |
|
||||
| [@vzts](https://github.com/vzts) | #7390 |
|
||||
| [@warelik](https://github.com/warelik) | direct commit / report |
|
||||
| [@way-art](https://github.com/way-art) | direct commit / report |
|
||||
| [@webmasterarbez](https://github.com/webmasterarbez) | #7504 |
|
||||
| [@wgordon17](https://github.com/wgordon17) | #8852 |
|
||||
| [@whale9820](https://github.com/whale9820) | direct commit / report |
|
||||
| [@Wibias](https://github.com/Wibias) | #7125 |
|
||||
| [@wilsonicdev](https://github.com/wilsonicdev) | direct commit / report |
|
||||
| [@Witroch4](https://github.com/Witroch4) | #6753, #6762, #6790, #7901, #7902 |
|
||||
| [@XCrag](https://github.com/XCrag) | direct commit / report |
|
||||
| [@xiaoyaner0201](https://github.com/xiaoyaner0201) | #8122, #8261, #8262 |
|
||||
| [@xier2012](https://github.com/xier2012) | #7036, #7050, #7052, #7053, #7056, #7059, #7060, #7061, #7166, #7299 |
|
||||
| [@xxue-z](https://github.com/xxue-z) | #7098 |
|
||||
| [@xz-dev](https://github.com/xz-dev) | #6323, #6330, #6714, #6727, #7004, #7012, #7027, #7673, #7700, #7747, #7776, #7843 |
|
||||
| [@yidecode](https://github.com/yidecode) | direct commit / report |
|
||||
| [@yinaoxiong](https://github.com/yinaoxiong) | #6805 |
|
||||
| [@diegosouzapw](https://github.com/diegosouzapw) | maintainer |
|
||||
|
||||
---
|
||||
|
||||
|
||||
37
README.md
37
README.md
@@ -63,8 +63,8 @@
|
||||
|
||||
| | v3.8.49 | **v3.8.50** | `v3.8.51+` |
|
||||
| ------------------------- | :-----: | :---------: | :---------: |
|
||||
| 🌐 Providers | 290 | **339** | more queued |
|
||||
| 🧠 Documented models | 1185 | **1202** | — |
|
||||
| 🌐 Providers | 291 | **339** | more queued |
|
||||
| 🧠 Documented models | 500+ | **1200+** | — |
|
||||
| 🖼️ Modality Bridge | — | 🆕 vision | video |
|
||||
| 📡 Radar free catalog | — | — | 🔭 next |
|
||||
| ⚖️ Quota-aware scheduling | — | — | 🔭 next |
|
||||
@@ -210,7 +210,7 @@ curl http://localhost:20128/v1/chat/completions \
|
||||
|
||||
</div>
|
||||
|
||||
<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint. 339 providers. Never stop building — OmniRoute picks the cheapest one that works. Six pillars: Never hit limits (auto-fallback across 339 providers in milliseconds, zero downtime) · Save up to 95% tokens (RTK + Caveman stacked compression cuts 15–95%, ~89% avg on tool-heavy sessions) · $0 to start (90+ free tiers, 56 free forever — no card needed) · Every tool works (33 coding agents through one config) · One endpoint (OpenAI ↔ Claude ↔ Gemini ↔ Responses API at /v1) · Production-grade (circuit breakers, TLS stealth, MCP 105 tools, A2A, memory, guardrails, evals — 25,000+ tests)."/>
|
||||
<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint. 339 providers. Never stop building — OmniRoute picks the cheapest one that works. Six pillars: Never hit limits (auto-fallback across 339 providers in milliseconds, zero downtime) · Save up to 95% tokens (RTK + Caveman stacked compression cuts 15–95%, ~89% avg on tool-heavy sessions) · $0 to start (90+ free tiers, 40+ free forever — no card needed) · Every tool works (33 coding agents through one config) · One endpoint (OpenAI ↔ Claude ↔ Gemini ↔ Responses API at /v1) · Production-grade (circuit breakers, TLS stealth, MCP 109 tools, A2A, memory, guardrails, evals — 25,000+ tests)."/>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
@@ -449,7 +449,7 @@ All **19** strategies — mix & match per combo step:
|
||||
|
||||
### 🧱 Resilience is built in (3 independent layers)
|
||||
|
||||
<img src="./docs/diagrams/resilience-layers.svg" width="100%" alt="OmniRoute resilience — 3 independent self-healing layers, the right layer for the right failure. Layer 1 provider circuit breaker (whole provider): trips only on 408/5xx, thresholds OAuth 10× / API-key 15× / local 2×, resets 60s/30s/15s into a HALF-OPEN probe, lazy recovery; while OPEN the combo reroutes to the next provider. Layer 2 connection cooldown (one key/account): base 5s OAuth / 3s API-key, exponential ×2 backoff with anti-thundering-herd guard, 429 honors Retry-After, success clears all error state; one cooling key is skipped while sibling keys keep serving. Layer 3 model lockout (one model): per-model 429, local 404 or mode denials lock just that model — never the whole connection. Terminal states (banned, expired, credits exhausted) are for the operator, not cooldowns."/>
|
||||
<img src="./docs/diagrams/resilience-layers.svg" width="100%" alt="OmniRoute resilience — 3 independent self-healing layers, the right layer for the right failure. Layer 1 provider circuit breaker (whole provider): trips only on 408/5xx, thresholds OAuth 3× / API-key 5× / local 2×, resets 60s/30s/15s into a HALF-OPEN probe, lazy recovery; while OPEN the combo reroutes to the next provider. Layer 2 connection cooldown (one key/account): base 5s OAuth / 3s API-key, exponential ×2 backoff with anti-thundering-herd guard, 429 honors Retry-After, success clears all error state; one cooling key is skipped while sibling keys keep serving. Layer 3 model lockout (one model): per-model 429, local 404 or mode denials lock just that model — never the whole connection. Terminal states (banned, expired, credits exhausted) are for the operator, not cooldowns."/>
|
||||
|
||||
<sub>📖 [Auto-Combo Engine](docs/routing/AUTO-COMBO.md) · [Resilience Guide](docs/architecture/RESILIENCE_GUIDE.md)</sub>
|
||||
|
||||
@@ -461,7 +461,7 @@ All **19** strategies — mix & match per combo step:
|
||||
|
||||
</div>
|
||||
|
||||
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — comparison table vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 339 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, built-in MCP server with 105 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA, 43 i18n UI locales, 100% MIT self-hosted. OmniRoute is the only one with the full set; competitors show a mix of checks, partials and crosses. Verified from each project's docs."/>
|
||||
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — comparison table vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 339 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, built-in MCP server with 109 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA, 43 i18n UI locales, 100% MIT self-hosted. OmniRoute is the only one with the full set; competitors show a mix of checks, partials and crosses. Verified from each project's docs."/>
|
||||
|
||||
<sub>📊 Full methodology & per-feature detail vs 9router, OpenRouter, CLIProxyAPI & LiteLLM → [`docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md`](docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md)</sub>
|
||||
|
||||
@@ -513,6 +513,25 @@ Pix copia-e-cola:
|
||||
|
||||
<br/>
|
||||
|
||||
## 📡 OmniRoute Radar
|
||||
|
||||
The main free-tier headline remains **~1.53B tokens/month** from the documented,
|
||||
pool-deduplicated catalog above. Temporary provider signup credits can separately lift the first
|
||||
month to **~2.15B**. Radar is an optional, signed catalog overlay for people who want fresher
|
||||
free-model availability between OmniRoute releases; the community catalog and every existing free
|
||||
feature remain free.
|
||||
|
||||
Supporters can receive the live catalog and additional provider opportunities. Its separate,
|
||||
mutable ceiling is **approximately 3B tokens/month at most**, depending on provider availability.
|
||||
That ceiling is not a guarantee: providers can change quotas, eligibility, models, or regions at
|
||||
any time.
|
||||
|
||||
Radar is opt-in and GET-only. The OmniRoute client does not upload prompts, traffic, provider
|
||||
configuration, usage telemetry, or local announcement-dismiss state. Learn about eligibility and
|
||||
the current catalog at **[radar.omniroute.online/planos](https://radar.omniroute.online/planos)**.
|
||||
|
||||
<br/>
|
||||
|
||||
<div align="center">
|
||||
|
||||
## ✨ What's New
|
||||
@@ -603,7 +622,7 @@ Pix copia-e-cola:
|
||||
|
||||
</div>
|
||||
|
||||
> The most complete catalog of any open-source router: **339 providers**, **90+ with a free tier**, **56 free forever**.
|
||||
> The most complete catalog of any open-source router: **339 providers**, **90+ with a free tier**, **40+ free forever**.
|
||||
|
||||
<div align="center">
|
||||
|
||||
@@ -748,7 +767,7 @@ Expose OmniRoute over **MCP**, **A2A**, a **REST API**, **webhooks** or a **remo
|
||||
<table>
|
||||
<tr><th align="left">Interface</th><th align="left">Endpoint / command</th><th align="left">Use it for</th></tr>
|
||||
<tr><td align="left" nowrap>🧰 <b>MCP (stdio)</b></td><td align="left" nowrap><code>omniroute --mcp</code></td><td align="left">Plug into Claude Desktop, Cursor, any MCP client</td></tr>
|
||||
<tr><td align="left" nowrap>🌊 <b>MCP (HTTP)</b></td><td align="left" nowrap><code>/api/mcp/stream</code></td><td align="left">Remote MCP — <b>105 tools</b>, 31 scopes, full audit trail</td></tr>
|
||||
<tr><td align="left" nowrap>🌊 <b>MCP (HTTP)</b></td><td align="left" nowrap><code>/api/mcp/stream</code></td><td align="left">Remote MCP — <b>109 tools</b>, 33 scopes, full audit trail</td></tr>
|
||||
<tr><td align="left" nowrap>📡 <b>MCP (SSE)</b></td><td align="left" nowrap><code>/api/mcp/sse</code></td><td align="left">Streaming MCP transport</td></tr>
|
||||
<tr><td align="left" nowrap>🤝 <b>A2A</b></td><td align="left" nowrap><code>/.well-known/agent.json</code></td><td align="left">Agent-to-agent, <b>JSON-RPC 2.0</b> + SSE, 6 skills</td></tr>
|
||||
<tr><td align="left" nowrap>🌐 <b>REST API</b></td><td align="left" nowrap><code>/v1/*</code></td><td align="left">OpenAI-compatible — chat, embeddings, images, audio, OCR</td></tr>
|
||||
@@ -1061,7 +1080,7 @@ same process on one port, so there is no separate CLI-only package today.
|
||||
<tr><td nowrap><b>Runtime</b></td><td>Node.js 22.x / 24.x LTS — <code>>=22.22.2 <23 || >=24.0.0 <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) — 117 domain modules, 145 migrations</td></tr>
|
||||
<tr><td nowrap><b>Database</b></td><td>better-sqlite3 (SQLite, WAL journaling) + LowDB (JSON legacy) — 117 domain modules, 148 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>
|
||||
@@ -1135,7 +1154,7 @@ same process on one port, so there is no separate CLI-only package today.
|
||||
<tr><th align="left">Document</th><th align="left">Description</th></tr>
|
||||
<tr><td nowrap><b><a href="docs/reference/API_REFERENCE.md">API Reference</a></b></td><td>All endpoints with examples</td></tr>
|
||||
<tr><td nowrap><b><a href="docs/openapi.yaml">OpenAPI Spec</a></b></td><td>OpenAPI 3.0 specification</td></tr>
|
||||
<tr><td nowrap><b><a href="open-sse/mcp-server/README.md">MCP Server</a></b></td><td>105 MCP tools, IDE configs, Python/TS/Go clients</td></tr>
|
||||
<tr><td nowrap><b><a href="open-sse/mcp-server/README.md">MCP Server</a></b></td><td>109 MCP tools, IDE configs, Python/TS/Go clients</td></tr>
|
||||
<tr><td nowrap><b><a href="docs/frameworks/MCP-SERVER.md">MCP Server Guide</a></b></td><td>MCP installation, transports, and tool reference</td></tr>
|
||||
<tr><td nowrap><b><a href="src/lib/a2a/README.md">A2A Server</a></b></td><td>JSON-RPC 2.0 protocol, skills, streaming, task mgmt</td></tr>
|
||||
<tr><td nowrap><b><a href="docs/frameworks/A2A-SERVER.md">A2A Server Guide</a></b></td><td>A2A agent card, tasks, skills, and streaming</td></tr>
|
||||
|
||||
76
bin/cli/commands/radar.mjs
Normal file
76
bin/cli/commands/radar.mjs
Normal file
@@ -0,0 +1,76 @@
|
||||
import { apiFetch } from "../api.mjs";
|
||||
import { t } from "../i18n.mjs";
|
||||
import { emit } from "../output.mjs";
|
||||
|
||||
const statusSchema = [
|
||||
{ key: "feed", header: "Feed" },
|
||||
{ key: "available", header: "Available" },
|
||||
{ key: "version", header: "Version" },
|
||||
{ key: "tier", header: "Tier" },
|
||||
{ key: "fetchedAt", header: "Fetched" },
|
||||
];
|
||||
|
||||
const syncSchema = [
|
||||
{ key: "feed", header: "Feed" },
|
||||
{ key: "status", header: "Status" },
|
||||
{ key: "version", header: "Version" },
|
||||
{ key: "reason", header: "Reason" },
|
||||
];
|
||||
|
||||
function exitCodeFor(response) {
|
||||
return Number.isInteger(response.exitCode) ? response.exitCode : response.status === 401 ? 4 : 1;
|
||||
}
|
||||
|
||||
export async function runRadarStatusCommand(opts = {}) {
|
||||
const response = await apiFetch("/api/radar/status", { acceptNotOk: true });
|
||||
if (!response.ok) return exitCodeFor(response);
|
||||
const data = await response.json();
|
||||
if (opts.output === "json") {
|
||||
emit(data, opts);
|
||||
return 0;
|
||||
}
|
||||
const rows = Object.entries(data.feeds ?? {}).map(([feed, value]) => ({
|
||||
feed,
|
||||
...(value && typeof value === "object" ? value : { available: false }),
|
||||
}));
|
||||
emit(rows, opts, statusSchema);
|
||||
return 0;
|
||||
}
|
||||
|
||||
export async function runRadarSyncCommand(opts = {}) {
|
||||
const response = await apiFetch("/api/radar/sync-all", {
|
||||
method: "POST",
|
||||
body: {},
|
||||
acceptNotOk: true,
|
||||
});
|
||||
if (!response.ok) return exitCodeFor(response);
|
||||
const data = await response.json();
|
||||
if (opts.output === "json") {
|
||||
emit(data, opts);
|
||||
return 0;
|
||||
}
|
||||
const rows = Object.entries(data).map(([feed, value]) => ({
|
||||
feed,
|
||||
...(value && typeof value === "object" ? value : { status: "error" }),
|
||||
}));
|
||||
emit(rows, opts, syncSchema);
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function registerRadar(program) {
|
||||
const radar = program.command("radar").description(t("radar.description"));
|
||||
radar
|
||||
.command("status")
|
||||
.description(t("radar.status"))
|
||||
.action(async (_opts, command) => {
|
||||
const code = await runRadarStatusCommand(command.optsWithGlobals());
|
||||
if (code !== 0) process.exitCode = code;
|
||||
});
|
||||
radar
|
||||
.command("sync")
|
||||
.description(t("radar.sync"))
|
||||
.action(async (_opts, command) => {
|
||||
const code = await runRadarSyncCommand(command.optsWithGlobals());
|
||||
if (code !== 0) process.exitCode = code;
|
||||
});
|
||||
}
|
||||
@@ -78,6 +78,7 @@ import { registerTokens } from "./tokens.mjs";
|
||||
import { registerConfigure } from "./configure.mjs";
|
||||
import { registerApiCommands } from "../api-commands/registry.mjs";
|
||||
import { registerPlugin } from "./plugin.mjs";
|
||||
import { registerRadar } from "./radar.mjs";
|
||||
|
||||
export function registerCommands(program) {
|
||||
registerMemory(program);
|
||||
@@ -161,4 +162,5 @@ export function registerCommands(program) {
|
||||
registerConfigure(program);
|
||||
registerApiCommands(program);
|
||||
registerPlugin(program);
|
||||
registerRadar(program);
|
||||
}
|
||||
|
||||
@@ -921,6 +921,11 @@
|
||||
"model": "Filter by model"
|
||||
}
|
||||
},
|
||||
"radar": {
|
||||
"description": "Inspect and synchronize the local Radar catalog feeds",
|
||||
"status": "Show local Radar settings and feed cache status",
|
||||
"sync": "Synchronize catalog, referrals, offers, and Intel through the local server"
|
||||
},
|
||||
"resilience": {
|
||||
"description": "Inspect and manage resilience mechanisms",
|
||||
"status": {
|
||||
|
||||
@@ -918,6 +918,11 @@
|
||||
"model": "Filtrar por model"
|
||||
}
|
||||
},
|
||||
"radar": {
|
||||
"description": "Inspecionar e sincronizar os feeds locais do catálogo Radar",
|
||||
"status": "Mostrar configurações locais e estado dos caches do Radar",
|
||||
"sync": "Sincronizar catálogo, indicações, ofertas e Intel pelo servidor local"
|
||||
},
|
||||
"resilience": {
|
||||
"description": "Inspecionar e gerenciar mecanismos de resiliência",
|
||||
"status": {
|
||||
|
||||
1
changelog.d/features/9830-radar-local-model-state.md
Normal file
1
changelog.d/features/9830-radar-local-model-state.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(radar):** Persist local model display-name/enabled overrides and hide/restore tombstones, with authenticated catalog controls and feed safety precedence ([#9830](https://github.com/diegosouzapw/OmniRoute/pull/9830))
|
||||
1
changelog.d/features/9836-radar-guided-combos.md
Normal file
1
changelog.d/features/9836-radar-guided-combos.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(radar):** add curated-family combo suggestions, a guided combo page, and the read-only Radar MCP catalog tool ([#9836](https://github.com/diegosouzapw/OmniRoute/pull/9836))
|
||||
1
changelog.d/features/9912-radar-supporter-offers.md
Normal file
1
changelog.d/features/9912-radar-supporter-offers.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(radar):** add a signed live offers feed and supporter offers dashboard ([#9912](https://github.com/diegosouzapw/OmniRoute/pull/9912))
|
||||
1
changelog.d/features/9923-radar-intel.md
Normal file
1
changelog.d/features/9923-radar-intel.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(radar):** add signed Intel insights, supporter recognition, and local Radar CLI commands ([#9923](https://github.com/diegosouzapw/OmniRoute/pull/9923))
|
||||
1
changelog.d/features/9926-radar-launch-news.md
Normal file
1
changelog.d/features/9926-radar-launch-news.md
Normal file
@@ -0,0 +1 @@
|
||||
- **feat(radar):** add a localized public news feed and dismissible dashboard launch banner, with the Radar announcement staged inactive for a separately authorized launch ([#9926](https://github.com/diegosouzapw/OmniRoute/pull/9926))
|
||||
@@ -27,6 +27,7 @@
|
||||
"providers-bailian-coding-plan.spec.ts": 240,
|
||||
"providers-management.spec.ts": 324,
|
||||
"proxy-registry.smoke.spec.ts": 218,
|
||||
"radar-guided-setup.spec.ts": 177,
|
||||
"resilience-plan-alignment.spec.ts": 382,
|
||||
"responsive.spec.ts": 21,
|
||||
"search-tools-studio.spec.ts": 133,
|
||||
@@ -36,4 +37,4 @@
|
||||
"traffic-inspector.spec.ts": 212,
|
||||
"translator-friendly.spec.ts": 115,
|
||||
"visual-resilience-smoke.spec.ts": 20
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,10 +205,10 @@ Runs on pull requests only.
|
||||
|
||||
Runs after `build`. Blocks merge on failure.
|
||||
|
||||
| Suite | Validates | Blocking |
|
||||
| ---------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
||||
| `test:vitest` | MCP server (105 tools), autoCombo, cache — vitest runner | Yes |
|
||||
| `test:vitest:ui` | UI component tests — vitest runner | **Blocking** — pre-existing failures are explicitly excluded in `vitest.config.ts`; new failures fail the job |
|
||||
| Suite | Validates | Blocking |
|
||||
| ---------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
||||
| `test:vitest` | MCP server (109 tools), autoCombo, cache — vitest runner | Yes |
|
||||
| `test:vitest:ui` | UI component tests — vitest runner | **Blocking** — pre-existing failures are explicitly excluded in `vitest.config.ts`; new failures fail the job |
|
||||
|
||||
### Nightly workflows (scheduled, advisory)
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ OmniRoute/
|
||||
| **.gitleaks.toml** | gitleaks secret-scan ruleset |
|
||||
| **.zizmor.yml** | zizmor GitHub-Actions security-lint config |
|
||||
| **socket.yml** | Socket.dev supply-chain config |
|
||||
| **news.json** | In-app release-notes feed (read by `src/shared/utils/releaseNotes.ts`) |
|
||||
| **news.json** | Localized v2 announcement feed; Radar launch item ships inactive |
|
||||
| **flake.nix** / **flake.lock** | Nix dev-shell definition + lock |
|
||||
| **.env** | Local secrets (gitignored — generated from `.env.example`) |
|
||||
|
||||
@@ -182,7 +182,7 @@ src/
|
||||
| `compliance/` | Audit log + provider audit — see `docs/security/COMPLIANCE.md` |
|
||||
| `compression/` | Compression engine glue (engines live in `open-sse/services/compression/`) |
|
||||
| `config/` | Runtime config helpers |
|
||||
| `db/` | 95+ domain DB modules + 144 migrations (always go through here for SQLite) |
|
||||
| `db/` | 95+ domain DB modules + 148 migrations (always go through here for SQLite) |
|
||||
| `quota/` | Quota Sharing Engine: `dimensions.ts` (types/Zod), `types.ts` (QuotaStore interface), `sqliteQuotaStore.ts`, `redisQuotaStore.ts`, `storeFactory.ts`, `fairShare.ts`, `burnRate.ts`, `planResolver.ts`, `planRegistry.ts`, `saturationSignals.ts`, `enforce.ts`, `spendRecorder.ts` — see `docs/routing/QUOTA_SHARE.md` |
|
||||
| `radar/` | Radar free-model catalog client: `feedSchema.ts`, `pinnedKeys.ts`, `verify.ts`, `sync.ts`, `applyFeed.ts`, `index.ts` (`getRadarCatalog()`) — see `docs/frameworks/RADAR.md` |
|
||||
| `display/` | UI formatting helpers (cost, latency, etc.) |
|
||||
@@ -196,7 +196,7 @@ src/
|
||||
| `memory/vectorStore.ts` | sqlite-vec v0.1.9 wrapper — KNN brute-force + hybrid RRF (FTS5 + vector, k=60). Lazy-init, degrades gracefully when sqlite-vec unavailable. (plan 21) |
|
||||
| `memory/reindex.ts` | `runReindexBatch()` — processes memories with `needs_reindex=1` in background; called by `POST /api/memory/reindex` and lazy-backfill path. (plan 21) |
|
||||
| `monitoring/` | Health checks, metrics emission |
|
||||
| `oauth/` | OAuth/import flows for 22 provider modules (agy, antigravity, claude, cline, codebuddy-cn, codex, cursor, devin-desktop, ghe-copilot, github, gitlab-duo, grok-cli-oauth, grok-cli, kilocode, kimi-coding, kiro, qoder, raycast, trae, xai-oauth, zed-hosted, zed) |
|
||||
| `oauth/` | OAuth/import flows for 22 provider modules (agy, antigravity, claude, cline, codebuddy-cn, codex, cursor, devin-desktop, ghe-copilot, github, gitlab-duo, grok-cli-oauth, grok-cli, kilocode, kimi-coding, kiro, qoder, raycast, trae, xai-oauth, zed-hosted, zed) |
|
||||
| `plugins/` | Plugin registry |
|
||||
| `promptCache/` | Anthropic-style prompt cache breakpoints |
|
||||
| `skills/` | Skills framework (built-in + marketplace + SkillsSH) — see `docs/frameworks/SKILLS.md` |
|
||||
@@ -209,7 +209,7 @@ src/
|
||||
| `cacheLayer.ts`, `idempotencyLayer.ts` | Request caching + idempotency |
|
||||
| (~30 more top-level files) | Specialized helpers (logEnv, modelsDevSync, piiSanitizer, etc.) |
|
||||
|
||||
### `src/db/` — Database (117 modules + 144 migrations)
|
||||
### `src/db/` — Database (117 modules + 148 migrations)
|
||||
|
||||
| Subdir | Purpose |
|
||||
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -256,6 +256,7 @@ src/
|
||||
| `utils/circuitBreaker.ts` | Provider circuit breaker (see `docs/architecture/RESILIENCE_GUIDE.md`) |
|
||||
| `utils/apiAuth.ts` | API key validation, scope checking |
|
||||
| `utils/fetchTimeout.ts` | Timeout/abort wrappers for upstream fetch |
|
||||
| `utils/releaseNotes.ts` | Closed v2/legacy announcement parser, localization and ID dismissal |
|
||||
|
||||
---
|
||||
|
||||
@@ -270,7 +271,7 @@ open-sse/
|
||||
├── translator/ # Format converters (9 request, 9 response, 9 helpers)
|
||||
├── transformer/ # Responses API ↔ Chat Completions (TransformStream)
|
||||
├── services/ # ~80+ service modules (combo, accountFallback, autoCombo, reasoningCache, claude code/chatgpt stealth, modelDeprecation, taskAwareRouter, workflowFSM, etc.)
|
||||
├── mcp-server/ # MCP server (105 tools, 3 transports, 31 scopes)
|
||||
├── mcp-server/ # MCP server (109 tools, 3 transports, 33 scopes)
|
||||
├── config/ # Provider/model registries, header config, model aliases
|
||||
├── utils/ # TLS client, proxy fetch/dispatcher, network helpers
|
||||
├── index.ts # Workspace entry
|
||||
@@ -406,7 +407,7 @@ open-sse/
|
||||
|
||||
| Doc | Purpose |
|
||||
| -------------------------- | ------------------------------------------------------------------- |
|
||||
| `MCP-SERVER.md` | MCP server: 105 tools, 3 transports, 31 scopes, REST endpoints |
|
||||
| `MCP-SERVER.md` | MCP server: 109 tools, 3 transports, 33 scopes, REST endpoints |
|
||||
| `A2A-SERVER.md` | A2A v0.3: JSON-RPC, 6 skills, REST helpers, agent card |
|
||||
| `AGENT_PROTOCOLS_GUIDE.md` | Unified guide: A2A vs ACP vs Cloud Agents |
|
||||
| `CLOUD_AGENT.md` | Codex Cloud / Devin / Jules orchestration |
|
||||
|
||||
@@ -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: 339 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, a built-in MCP server with 105 tools, A2A protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, desktop/Termux/PWA, 43 UI locales and 100% MIT self-hosted. 9router has free providers, RTK compression and translation but no MCP, A2A, memory, guardrails, cloud agents or stealth. OpenRouter is a hosted SaaS with 400+ models, guardrails and a hosted MCP but is not self-hosted and lacks A2A, memory, cloud agents and stealth. CLIProxyAPI is a light OAuth proxy with two routing strategies. LiteLLM has 100+ providers, A2A and extensive guardrails but no memory, compression, free tier, stealth or cloud agents.">
|
||||
<svg viewBox="0 0 1200 780" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Comparison table: OmniRoute versus 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute is the only one with the full set: 339 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, a built-in MCP server with 109 tools, A2A protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, desktop/Termux/PWA, 43 UI locales and 100% MIT self-hosted. 9router has free providers, RTK compression and translation but no MCP, A2A, memory, guardrails, cloud agents or stealth. OpenRouter is a hosted SaaS with 400+ models, guardrails and a hosted MCP but is not self-hosted and lacks A2A, memory, cloud agents and stealth. CLIProxyAPI is a light OAuth proxy with two routing strategies. LiteLLM has 100+ providers, A2A and extensive guardrails but no memory, compression, free tier, stealth or cloud agents.">
|
||||
<desc>Static-header comparison table where each capability row fades in top to bottom; the OmniRoute column is highlighted and shows a check or a leading value in every row, while competitors show a mix of checks, partials and crosses.</desc>
|
||||
<defs>
|
||||
<pattern id="gC" width="32" height="32" patternUnits="userSpaceOnUse"><path d="M 32 0 L 0 0 0 32" fill="none" stroke="#ffffff" stroke-opacity="0.05" stroke-width="1"/></pattern>
|
||||
@@ -57,7 +57,7 @@
|
||||
</g>
|
||||
<g opacity="0"><animate attributeName="opacity" values="0;1" dur="0.4s" begin="0.51s" fill="freeze"/>
|
||||
<text x="44" y="364" font-size="14.5" fill="#c9d1d9">Built-in MCP server (own tools)</text>
|
||||
<text x="440" y="364" text-anchor="middle" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="15" font-weight="800" fill="#7ee787">105</text>
|
||||
<text x="440" y="364" text-anchor="middle" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="15" font-weight="800" fill="#7ee787">109</text>
|
||||
<use href="#no" x="604" y="359"/>
|
||||
<use href="#mid" x="760" y="359"/>
|
||||
<use href="#no" x="916" y="359"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@@ -1,4 +1,4 @@
|
||||
<svg viewBox="0 0 1200 540" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The OmniRoute promise: one endpoint, 339 providers — never stop building, OmniRoute picks the cheapest one that works. Six pillars. Never hit limits: auto-fallback across 339 providers in milliseconds, quota out means the next provider takes over with zero downtime. Save up to 95 percent of tokens: RTK plus Caveman stacked compression cuts 15 to 95 percent of eligible tokens, about 89 percent average on tool-heavy sessions. Zero dollars to start: 90+ providers with a free tier, 56 free forever — Qoder, Pollinations, Cloudflare, SiliconFlow — no card needed. Every tool works: 33 coding agents including Claude Code, Codex, Cursor, Cline, Copilot and Antigravity through one config. One endpoint: OpenAI, Claude, Gemini and Responses API translation — point any tool at /v1 and it just works. Production-grade: circuit breakers, TLS stealth, MCP with 105 tools, A2A, memory, guardrails, evals — 25,000+ tests.">
|
||||
<svg viewBox="0 0 1200 540" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The OmniRoute promise: one endpoint, 339 providers — never stop building, OmniRoute picks the cheapest one that works. Six pillars. Never hit limits: auto-fallback across 339 providers in milliseconds, quota out means the next provider takes over with zero downtime. Save up to 95 percent of tokens: RTK plus Caveman stacked compression cuts 15 to 95 percent of eligible tokens, about 89 percent average on tool-heavy sessions. Zero dollars to start: 90+ providers with a free tier, 40+ free forever — Qoder, Pollinations, Cloudflare, SiliconFlow — no card needed. Every tool works: 33 coding agents including Claude Code, Codex, Cursor, Cline, Copilot and Antigravity through one config. One endpoint: OpenAI, Claude, Gemini and Responses API translation — point any tool at /v1 and it just works. Production-grade: circuit breakers, TLS stealth, MCP with 109 tools, A2A, memory, guardrails, evals — 25,000+ tests.">
|
||||
<desc>Animated promise card: six pillar tiles fade in in reading order, then a soft colored border highlight sweeps from tile to tile in a continuous cycle.</desc>
|
||||
<defs>
|
||||
<pattern id="gridPaperP" width="32" height="32" patternUnits="userSpaceOnUse">
|
||||
@@ -73,7 +73,7 @@
|
||||
<circle cx="6.6" cy="6.6" r="1.4" fill="#fdcb6e" stroke="none"/>
|
||||
</g>
|
||||
<text x="862" y="170" font-size="18" font-weight="800" fill="#fdcb6e">$0 to start</text>
|
||||
<text x="826" y="204" font-size="13.5" fill="#a1a1aa">90+ providers with a free tier, 56 free</text>
|
||||
<text x="826" y="204" font-size="13.5" fill="#a1a1aa">90+ providers with a free tier, 40+ free</text>
|
||||
<text x="826" y="226" font-size="13.5" fill="#a1a1aa">forever — Qoder, Pollinations, Cloudflare,</text>
|
||||
<text x="826" y="248" font-size="13.5" fill="#a1a1aa">SiliconFlow… No card needed.</text>
|
||||
</g>
|
||||
@@ -125,7 +125,7 @@
|
||||
<path d="M 7,11 L 10,14 L 15.4,8.2"/>
|
||||
</g>
|
||||
<text x="862" y="354" font-size="18" font-weight="800" fill="#7ee787">Production-grade</text>
|
||||
<text x="826" y="388" font-size="13.5" fill="#a1a1aa">Circuit breakers, TLS stealth, MCP (105</text>
|
||||
<text x="826" y="388" font-size="13.5" fill="#a1a1aa">Circuit breakers, TLS stealth, MCP (109</text>
|
||||
<text x="826" y="410" font-size="13.5" fill="#a1a1aa">tools), A2A, memory, guardrails, evals —</text>
|
||||
<text x="826" y="432" font-size="13.5" fill="#a1a1aa">25,000+ tests.</text>
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
@@ -1,14 +1,14 @@
|
||||
---
|
||||
title: "OmniRoute MCP Server Documentation"
|
||||
version: 3.8.40
|
||||
lastUpdated: 2026-06-28
|
||||
version: 3.8.50
|
||||
lastUpdated: 2026-08-08
|
||||
---
|
||||
|
||||
# OmniRoute MCP Server Documentation
|
||||
|
||||
> Model Context Protocol server with 105 tools across routing, cache, compression, memory, skills, proxy, pool, and context source operations.
|
||||
> Model Context Protocol server with 109 tools across routing, cache, compression, memory, skills, proxy, pool, Radar, and context source operations.
|
||||
>
|
||||
> Source of truth: `open-sse/mcp-server/server.ts` computes **105 unique tools** with `countUniqueMcpTools()`: 42 canonical definitions (including the six CCR lifecycle tools and the agent-skills trio), plus memory (3), skills (4), GitHub skills (3), pool (6), gamification (8), plugins (8), Notion (6), Obsidian (22), and two RTK-only compression tools.
|
||||
> Source of truth: `open-sse/mcp-server/server.ts` computes **109 unique tools** with `countUniqueMcpTools()`: 44 canonical definitions (including the six CCR lifecycle tools, the agent-skills trio, and `omniroute_radar_catalog`), plus memory (3), skills (4), GitHub skills (3), pool (6), gamification (8), plugins (8), Notion (6), Obsidian (22), local corpus (3), and two RTK-only compression tools.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -64,7 +64,7 @@ Cursor, Cline, and compatible MCP client setup.
|
||||
|
||||
---
|
||||
|
||||
## Essential Tools (8) — Phase 1
|
||||
## Essential Tools (13) — Phase 1
|
||||
|
||||
| Tool | Scopes | Description |
|
||||
| :------------------------------ | :-------------------- | :------------------------------------------------------------ |
|
||||
@@ -72,16 +72,15 @@ Cursor, Cline, and compatible MCP client setup.
|
||||
| `omniroute_list_combos` | `read:combos` | All configured combos with strategies (optional metrics) |
|
||||
| `omniroute_get_combo_metrics` | `read:combos` | Performance metrics for a specific combo |
|
||||
| `omniroute_switch_combo` | `write:combos` | Activate or deactivate a combo |
|
||||
| `omniroute_create_combo` | `write:combos` | Create a validated combo through the existing combo API |
|
||||
| `omniroute_check_quota` | `read:quota` | Quota used/total, percent remaining, reset time, token health |
|
||||
| `omniroute_route_request` | `execute:completions` | Send a chat completion through OmniRoute routing |
|
||||
| `omniroute_cost_report` | `read:usage` | Cost report by period (session/day/week/month) |
|
||||
| `omniroute_list_models_catalog` | `read:models` | Full model catalog with capabilities, status, pricing |
|
||||
|
||||
## Phase 1 — Search
|
||||
|
||||
| Tool | Scopes | Description |
|
||||
| :--------------------- | :--------------- | :--------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `omniroute_web_search` | `execute:search` | Web search through OmniRoute search gateway (Serper/Brave/Perplexity/Exa/Tavily/Google PSE/Linkup/SearchAPI/SearXNG) with failover |
|
||||
| `omniroute_radar_catalog` | `read:radar` | Local signed Radar catalog; optional provider/family filters |
|
||||
| `omniroute_tool_search` | `read:tools` | Discover tools from the registered MCP catalog |
|
||||
| `omniroute_web_search` | `execute:search` | Web search through the configured search providers |
|
||||
| `omniroute_web_fetch` | `execute:search` | Fetch web content through the configured fetch providers |
|
||||
|
||||
## Advanced Tools (11) — Phase 2
|
||||
|
||||
@@ -227,7 +226,7 @@ See [AGENT-SKILLS.md](./AGENT-SKILLS.md) for the full catalog and how external a
|
||||
|
||||
## Related Frameworks (v3.8.0)
|
||||
|
||||
computed = 105, computed by `countUniqueMcpTools()`) is intentionally
|
||||
The MCP tool inventory above (109 unique tools, computed by `countUniqueMcpTools()`) is intentionally
|
||||
scoped to runtime routing/cache/compression/memory/skills/proxy/context-source operations. Two adjacent
|
||||
frameworks ship alongside the MCP server in v3.8.0 and are documented separately:
|
||||
|
||||
@@ -369,7 +368,7 @@ MCP tool, prompt, and resource registries can compress descriptions at registrat
|
||||
|
||||
Description compression shrinks each tool's metadata; **tool-cardinality reduction** goes one step further by reducing _how many_ tools are announced at all. Advertising fewer tools in the `tools/list` manifest cuts the per-request token cost the client's model pays for the tool catalog ("layer 5" compression). The implementation is a pure, stateless filter in `open-sse/mcp-server/toolCardinality.ts` (`reduceToolManifest`), wired into the registration loop in `createMcpServer()` (`open-sse/mcp-server/server.ts`).
|
||||
|
||||
**Opt-in, off by default.** The filter only runs when at least one of two environment variables is set; with neither set, all 105 tools are announced unchanged.
|
||||
**Opt-in, off by default.** The filter only runs when at least one of two environment variables is set; with neither set, all 109 tools are announced unchanged.
|
||||
|
||||
| Variable | Mode |
|
||||
| :--------------- | :-------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
title: "Radar Free-Model Catalog"
|
||||
version: 3.8.50
|
||||
lastUpdated: 2026-08-08
|
||||
lastUpdated: 2026-08-13
|
||||
---
|
||||
|
||||
# Radar Free-Model Catalog
|
||||
|
||||
> **Source of truth:** `src/lib/radar/`, `src/lib/db/radar.ts`, `src/app/api/radar/`
|
||||
> **Last updated:** 2026-08-08 — v3.8.50
|
||||
> **Last updated:** 2026-08-13 — v3.8.50
|
||||
|
||||
Radar is an **optional add-on** that overlays a signed, freshly-curated free-model
|
||||
catalog on top of the release baseline (`FREE_MODEL_BUDGETS` in
|
||||
@@ -15,11 +15,12 @@ catalog on top of the release baseline (`FREE_MODEL_BUDGETS` in
|
||||
faster than release cadence — providers add, shrink, or discontinue free quotas between
|
||||
releases, and the baseline catalog can only be refreshed when a new version ships.
|
||||
|
||||
**Nothing that is free today stops being free.** Radar never removes or paywalls a
|
||||
baseline entry; it only refreshes limits/status fields at read time and can layer in
|
||||
newly-discovered free models between releases. The baseline catalog itself is never
|
||||
mutated on disk — see [Read-time overlay merge rules](#read-time-overlay-merge-rules)
|
||||
below.
|
||||
**Nothing that is free today stops being free because of the remote feed.** Radar never
|
||||
paywalls a baseline entry; it only refreshes limits/status fields at read time and can
|
||||
layer in newly-discovered free models between releases. An operator can still hide a
|
||||
model locally, and can restore it from the same dashboard. The baseline catalog itself
|
||||
is never mutated on disk — see
|
||||
[Read-time overlay merge rules](#read-time-overlay-merge-rules) below.
|
||||
|
||||
---
|
||||
|
||||
@@ -29,14 +30,39 @@ The following status distinguishes what this OSS release implements from later R
|
||||
workstreams. It is a code-level status, not a promise that a particular hosted deployment
|
||||
or external integration is currently available.
|
||||
|
||||
| Area | Status in this release |
|
||||
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Signed catalog client | Implemented behind `RADAR_ENABLED`, with separate opt-in, Ed25519 verification, local encrypted settings/cache, non-destructive overlay, scheduler, and dashboard. |
|
||||
| Contributor activation | The dashboard links to the server-hosted GitHub claim flow and accepts an existing `omr_…` key. Contributor eligibility is resolved by the private service; the OSS client contains no GitHub token or issuance logic. |
|
||||
| Supporter-key activation | Implemented. The raw key is validated, encrypted at rest, masked on reads, and sent only by the server-side sync. Changing or clearing the key invalidates both entitlement-sensitive feed caches. |
|
||||
| Referral links | Implemented as a separately signed, hourly-refreshed feed. Fixed links are available to the community tier immediately; limited campaigns remain live-tier data. |
|
||||
| Payments and transactional email | Not implemented in the OSS client. Purchase, donation, receipt review, and mail delivery belong to the private service and its later operational workstream. |
|
||||
| Research-agent workstream | Not part of this client release. Curated feed contents remain server-side data; no autonomous research agent runs in an OmniRoute installation. |
|
||||
| Area | Status in this release |
|
||||
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Signed catalog client | Implemented behind `RADAR_ENABLED`, with separate opt-in, Ed25519 verification, local encrypted settings/cache, persistent display/enabled overrides, reversible tombstones, scheduler, and dashboard. |
|
||||
| Contributor activation | The dashboard links to the server-hosted GitHub claim flow and accepts an existing `omr_…` key. Contributor eligibility is resolved by the private service; the OSS client contains no GitHub token or issuance logic. |
|
||||
| Supporter-key activation | Implemented. The raw key is validated, encrypted at rest, masked on reads, and sent only by server-side sync. Changing or clearing the key invalidates all four entitlement-sensitive feed caches. |
|
||||
| Referral links | Implemented as a separately signed, hourly-refreshed feed. Fixed links are available to the community tier immediately; limited campaigns remain live-tier data. |
|
||||
| Supporter offers | Implemented as a separate signed, live-only feed and dashboard page. The client revalidates the closed benefit schema, preserves the last good cache, filters expired entries, and labels partner offers explicitly. |
|
||||
| Intel and supporter recognition | Implemented as a strict signed live-only feed with Radar-owned ELO, factual catalog freshness/trend, a verified local supporter badge, dashboard page, and local-only CLI status/sync commands. |
|
||||
| Payments and transactional email | Not implemented in the OSS client. Purchase, donation, receipt review, recovery, and mail delivery belong to the private service; hosted availability still depends on its supervised deploy and provider configuration. |
|
||||
| Research-agent workstream | Not part of this client release. Curated feed contents remain server-side data; no autonomous research agent runs in an OmniRoute installation. |
|
||||
|
||||
---
|
||||
|
||||
## Public announcement reader
|
||||
|
||||
The generic announcement reader is separate from the Radar feature flag. The dashboard Home and
|
||||
Changelog viewer fetch the repository's public `news.json` through a plain `GET` to
|
||||
`NEWS_JSON_URL` (`src/shared/utils/releaseNotes.ts`). They send no Radar setting, prompt, provider
|
||||
configuration, usage record, or local dismissal state.
|
||||
|
||||
`news.json` uses the closed v2 schema implemented by `parseNewsPayload()`:
|
||||
|
||||
- `schemaVersion: 2` and a bounded `items[]` collection;
|
||||
- stable, unique announcement `id` values;
|
||||
- explicit `active` and ISO `publishedAt` fields;
|
||||
- required English copy with optional localized copy;
|
||||
- optional credential-free HTTPS links and an allowlisted icon;
|
||||
- newest-active-first selection, locale fallback to English, and per-ID local dismissal.
|
||||
|
||||
The parser temporarily accepts the former singular `{ active, title, message, ... }` shape so
|
||||
older forks can migrate without a broken Changelog view. Invalid feeds are inert. The Radar launch
|
||||
entry ships with `active: false`; changing it to `true` is a separate post-merge, post-deploy
|
||||
release action and does not change `RADAR_ENABLED` or the independent feed-sync opt-in.
|
||||
|
||||
---
|
||||
|
||||
@@ -48,15 +74,16 @@ Radar is gated end-to-end by the `RADAR_ENABLED` feature flag
|
||||
|
||||
**When the flag is off, the surface does not exist:**
|
||||
|
||||
- `GET /api/radar/catalog`, `POST /api/radar/sync`, `POST /api/radar/settings` all
|
||||
- All `/api/radar/*` endpoints, including local model-state reads and writes,
|
||||
return `404` before touching any Radar module.
|
||||
- The dashboard screens (`/dashboard/radar`, `/dashboard/radar/setup`) render
|
||||
- The dashboard screens (`/dashboard/radar`, `/dashboard/radar/setup`,
|
||||
`/dashboard/radar/combos`, `/dashboard/radar/offers`, `/dashboard/radar/intel`) render
|
||||
`notFound()`.
|
||||
- `getRadarCatalog()` (`src/lib/radar/index.ts`) returns the untouched baseline —
|
||||
same entry count, same values, every entry tagged `origin: "baseline"` — and never
|
||||
reads the feed cache.
|
||||
- No network call is ever made; `syncRadar()` (`src/lib/radar/sync.ts`) returns
|
||||
`{ status: "disabled" }` at step 1 without touching `fetch`.
|
||||
- No Radar network call is ever made; each sync module returns `{ status: "disabled" }`
|
||||
before touching `fetch`.
|
||||
|
||||
This is a strict superset gate: flipping the flag on unlocks the _screens_, nothing
|
||||
more. It does not upload data, does not start a background sync, and does not change
|
||||
@@ -78,14 +105,17 @@ Opt-in false → { status: "opt_out" } — no network call
|
||||
|
||||
When both are on, the sync path is:
|
||||
|
||||
1. `GET <feed base URL>/v1/catalog/latest` with an optional `Authorization: Bearer
|
||||
<supporter key>` header (see below).
|
||||
1. `GET <feed base URL>/v1/catalog/latest` with `x-omniroute-radar-schema: 2` and an optional
|
||||
`Authorization: Bearer <supporter key>` header (see below). Servers default to the separately
|
||||
signed v1 transition artifact when the schema header is absent, so older installed clients keep
|
||||
receiving updates.
|
||||
2. Nothing about the request, the operator, or their traffic is uploaded — it is a
|
||||
plain, unauthenticated-by-default GET. OmniRoute never posts usage data, provider
|
||||
configuration, or model traffic to the feed service.
|
||||
3. The response is verified, validated, and cached locally (see
|
||||
[Security model](#security-model)). Radar has exactly two server-side network paths:
|
||||
`syncRadar()` for the catalog and `syncRadarReferrals()` for the standalone referrals feed.
|
||||
[Security model](#security-model)). Radar has exactly four server-side network paths:
|
||||
`syncRadar()` for the catalog, `syncRadarReferrals()` for referrals, and
|
||||
`syncRadarOffers()` / `syncRadarIntel()` for supporter-only offers and Intel.
|
||||
|
||||
The **supporter key** is an optional Bearer token (`radar_settings.supporter_key`)
|
||||
that lets the feed service decide which tier to serve (see
|
||||
@@ -95,7 +125,7 @@ that lets the feed service decide which tier to serve (see
|
||||
helpers (`src/lib/db/encryption.ts`) used for provider credentials.
|
||||
- Set via `POST /api/radar/settings` (`{ supporterKey: "omr_" + 40 hex chars }`) and
|
||||
**never echoed back** — the response returns a masked form (`omr_****abcd`).
|
||||
- Changing or clearing it atomically invalidates both the catalog and referrals caches. The
|
||||
- Changing or clearing it atomically invalidates the catalog, referrals, offers, and Intel caches. The
|
||||
next sync/read resolves the new entitlement server-side; saving a key does not itself make
|
||||
a network request or consume a single-use activation key.
|
||||
- Sent to the feed service as a Bearer token on the sync GET — nothing else about the
|
||||
@@ -128,6 +158,29 @@ client component never reads `process.env` itself.
|
||||
| `RADAR_CONTRIBUTOR_CLAIM_URL` | Overrides the contributor-claim URL (default `https://radar.omniroute.online/auth/github`). |
|
||||
| `RADAR_SUPPORTER_PLANS_URL` | Overrides the supporter-plans URL (default `https://radar.omniroute.online/planos`). |
|
||||
|
||||
### Recovering a lost supporter key
|
||||
|
||||
The hosted service's recovery entry point is `https://radar.omniroute.online/recover`; it is also
|
||||
linked from the plans page. Recovery remains entirely outside the OSS client because the local
|
||||
installation never receives the purchaser/contributor e-mail and cannot reconstruct a raw key from
|
||||
its encrypted settings.
|
||||
|
||||
1. Submit the e-mail associated with the key. The service returns the same accepted page whether a
|
||||
recoverable license exists or not, so the form does not enumerate accounts.
|
||||
2. If eligible, the delivery worker sends a short-lived, one-use link. Opening it immediately moves
|
||||
the token into a transient encrypted `HttpOnly`/`Secure` cookie and redirects to the clean
|
||||
`/recover` URL; the page contains no token, e-mail, old key, or replacement key.
|
||||
3. Confirm the revocation. The private service revokes the prior key, creates the replacement with
|
||||
the same plan/expiration, and queues it for e-mail in one transaction. The replacement is never
|
||||
returned to the browser.
|
||||
4. Paste the replacement into `/dashboard/radar`. The old key must now degrade to `community`; the
|
||||
replacement must produce a verified `live` sync. Reopening the same recovery link must fail with
|
||||
a generic invalid/expired response.
|
||||
|
||||
The hosted recovery route and mail worker can be present in code while still unavailable in a given
|
||||
deployment. Do not call the flow production-ready until the server has been deployed, the delivery
|
||||
provider has been configured with a controlled recipient, and the full one-use link has been tested.
|
||||
|
||||
Once a visitor has a key (`omr_` + 40 hex chars), the activation screen
|
||||
(`src/app/(dashboard)/dashboard/radar/page.tsx`) has a paste-key input as the primary
|
||||
path: pasting a key and submitting sends `POST /api/radar/settings`
|
||||
@@ -141,6 +194,57 @@ paste a new one — the raw key is never redisplayed. The two claim/plans button
|
||||
remain the way to _obtain_ a key in the first place; this input is where an operator
|
||||
who already has one activates it.
|
||||
|
||||
### End-to-end activation and guided setup
|
||||
|
||||
The private feed service and this OSS client have a deliberately narrow boundary: the service
|
||||
issues and validates the supporter key, while the local OmniRoute installation encrypts the key,
|
||||
syncs signed artifacts server-side, and guides provider setup. The assisted validation order is:
|
||||
|
||||
1. Obtain a newly issued or recovered key from the contributor claim, plans/checkout, recovery
|
||||
journey, or an authorized private server operator. Do not paste the raw key into logs,
|
||||
screenshots, issue comments, or command-line arguments.
|
||||
2. Enable the `RADAR_ENABLED` feature flag on the local OmniRoute installation. This exposes the UI
|
||||
but remains network-inert until the separate opt-in is saved.
|
||||
3. Open `/dashboard/radar`, paste the key, and activate. The browser sends one local
|
||||
`POST /api/radar/settings` with `{ optIn: true, supporterKey }`; the key is encrypted locally and
|
||||
the response contains only `omr_****<last4>`.
|
||||
4. Let the activation screen run its catalog sync, or select **Sync now**. Confirm that the page
|
||||
reports `live`, a feed version, and a fetch time. For an authenticated local diagnostic,
|
||||
`GET /api/radar/status` reports opt-in/key presence and the four cache states without returning
|
||||
the key. `POST /api/radar/sync-all` can refresh catalog, referrals, offers, and Intel explicitly.
|
||||
5. Open `/dashboard/radar/setup?provider=<provider>`. Follow the provider-owned credential URL,
|
||||
select **Add API key**, save through the real provider form, return to the guide, and run
|
||||
**Test connection**. The guide uses the normal `/api/providers` and
|
||||
`/api/providers/<connection-id>/test` routes; it does not create a parallel Radar credential.
|
||||
6. Open `/dashboard/radar/combos` after at least two compatible provider connections are active.
|
||||
Review the suggested family and create the combo through the existing combo API. Offers and
|
||||
Intel remain separate live-only signed caches and can be checked on their dedicated Radar pages.
|
||||
7. Reload `/dashboard/radar` and the setup page. The opt-in, masked-key state, verified cache, saved
|
||||
provider connection, and test action must survive the reload. Capture evidence only after the
|
||||
raw key and provider credential are no longer visible.
|
||||
|
||||
Saving a key is not itself proof of live entitlement. The proof is the combination of the private
|
||||
service's `GET /v1/license/check` result, the OSS catalog's served `live` tier, a verified signed
|
||||
cache, and the real provider connection/test flow. An invalid, expired, or revoked key safely
|
||||
degrades the catalog to `community`; it must not be reported as a successful live-key validation.
|
||||
|
||||
### Private admin-panel link
|
||||
|
||||
`RADAR_ADMIN_URL` optionally adds **Radar Admin ↗** immediately after the user-facing
|
||||
Radar item in the Costs sidebar section. It has deliberately no default: when the variable is
|
||||
unset or invalid, the static sidebar, command palette, and sidebar-customization screen contain no
|
||||
admin item and no private URL.
|
||||
|
||||
The value is resolved server-side and relayed through the management-authenticated
|
||||
`GET /api/settings` response only to an authenticated dashboard session, or to the trusted
|
||||
loopback owner during a local no-login bootstrap. CLI, internal-service, and manage-scope API-key
|
||||
authentication do not receive it. The browser validates the response again before materializing
|
||||
the external link, which opens with `noopener noreferrer`.
|
||||
|
||||
Use a credential-free HTTPS tunnel/tailnet URL. Plain HTTP is accepted only for a loopback SSH
|
||||
forward such as `http://127.0.0.1:9351`; other schemes, embedded credentials, malformed URLs, and
|
||||
remote HTTP destinations fail closed and leave navigation inert.
|
||||
|
||||
---
|
||||
|
||||
## Security model
|
||||
@@ -271,6 +375,54 @@ Four rules, in order of precedence:
|
||||
entry (`tombstones` set), the feed re-adding that `provider:modelId` in a later
|
||||
version does not bring it back.
|
||||
|
||||
The editable fields and tombstones are persisted in
|
||||
`radar_local_model_state` (migration `153_radar_local_model_state.sql`). The public DB
|
||||
adapter (`src/lib/db/radar.ts`) converts those rows into the `localOverrides` map and
|
||||
`tombstones` set used by `applyFeed()`; production `getRadarCatalog()` loads that state
|
||||
after the flag, cache, and schema gates pass. Only `displayName` and `enabled` are
|
||||
operator-editable. Provider/model identity, feed provenance, quota, capabilities, ToS,
|
||||
and setup data cannot be written through this surface.
|
||||
|
||||
The dashboard exposes four local actions:
|
||||
|
||||
- **Edit** changes the local display name and enabled state.
|
||||
- **Reset local changes** clears both editable fields without changing a tombstone.
|
||||
- **Hide** creates a tombstone, so later feed updates cannot recreate the row.
|
||||
- **Restore** removes the tombstone; any separately-saved override remains in effect.
|
||||
|
||||
A feed `enabled: false` remains the safety exception: it wins over a stale local
|
||||
`enabled: true`, keeps the merged entry disabled, and records `disabledBy: "radar"`.
|
||||
|
||||
Catalog publications use `schemaVersion: 2`. `contextWindow` and each of `tools`, `vision`, and
|
||||
`thinking` are independently `number | null` / `boolean | null`: `null` means unknown, while
|
||||
`false` means a D16-confirmed official provider source explicitly says the capability is absent.
|
||||
Internal OmniRoute registry/model-spec flags are never promoted directly to feed facts. The client
|
||||
still accepts v1 snapshots; because the old builder used `false` as an absence placeholder, v1 `false` is
|
||||
normalized to unknown while v1 `true` remains factual. Unknown schema versions fail closed and the
|
||||
last valid cache remains available. Every v2 model with a non-null context/capability must carry a
|
||||
credential-free HTTPS `metadataEvidenceUrls[]`; otherwise schema validation fails and the cache is
|
||||
not replaced. The catalog table renders all three states as `✓`, `✕`, and `?`.
|
||||
|
||||
### Guided combos and MCP access
|
||||
|
||||
Confirmed `familyId` values survive the read-time overlay and drive the pure
|
||||
`buildRadarComboSuggestions()` module (`src/lib/radar/comboSuggestions.ts`). A family is suggested
|
||||
only when at least two distinct providers have active connections and expose the exact curated model
|
||||
ID. Disabled models, inactive providers, missing model IDs, singleton families, and ambiguous
|
||||
alias/prefix matches fail closed. Suggestions use the existing `priority` strategy, ordering the
|
||||
largest recurring monthly budget first; the UI creates them only through `POST /api/combos`.
|
||||
|
||||
The guided UI lives at `/dashboard/radar/combos`. It reads only the local
|
||||
`GET /api/radar/catalog` and `GET /api/combos/builder/options` endpoints. It never triggers Radar sync,
|
||||
reads provider credentials, or writes directly to the combo database.
|
||||
|
||||
MCP clients can read the same local projection with `omniroute_radar_catalog` (`read:radar`). The
|
||||
optional `provider`, `familyId`, and `enabledOnly` filters are evaluated after one local
|
||||
`GET /api/radar/catalog` read. Its closed output includes catalog metadata plus provider/model,
|
||||
display name, `familyId`, quota, capabilities, enabled state, origin, and `disabledBy`; setup URLs,
|
||||
steps, connections, e-mail addresses, keys, and referral data are never returned. This tool is
|
||||
read-only and never invokes `/api/radar/sync`.
|
||||
|
||||
### Provenance markers
|
||||
|
||||
Every merged entry carries an `origin` field the UI renders as a badge:
|
||||
@@ -284,30 +436,41 @@ Every merged entry carries an `origin` field the UI renders as a badge:
|
||||
|
||||
## Local surfaces — never a feed proxy
|
||||
|
||||
Five local routes back the UI, all under `src/app/api/radar/`:
|
||||
The local Radar route families below back the UI under `src/app/api/radar/`:
|
||||
|
||||
| Route | Method | Purpose |
|
||||
| ---------------------- | ------ | --------------------------------------------------------------------------------------------------------------------- |
|
||||
| `/api/radar/catalog` | GET | Returns the merged catalog (`getRadarCatalog()`) from the local cache. |
|
||||
| `/api/radar/sync` | POST | Triggers `syncRadar()` server-side; returns the resulting status. |
|
||||
| `/api/radar/settings` | GET | Returns `{ optIn, hasSupporterKey, supporterKeyMasked }` — never the raw key. |
|
||||
| `/api/radar/settings` | POST | Sets opt-in and/or the (encrypted) supporter key. |
|
||||
| `/api/radar/referrals` | GET | Returns `{ fixed, campaigns, tier }` from the local cache — see [Referral links](#referral-links-free-credits) below. |
|
||||
| Route | Method | Purpose |
|
||||
| ------------------------------ | ------ | --------------------------------------------------------------------------------------------------------------------- |
|
||||
| `/api/radar/catalog` | GET | Returns the merged catalog (`getRadarCatalog()`) from the local cache. |
|
||||
| `/api/radar/sync` | POST | Triggers `syncRadar()` server-side; returns the resulting status. |
|
||||
| `/api/radar/settings` | GET | Returns `{ optIn, hasSupporterKey, supporterKeyMasked }` — never the raw key. |
|
||||
| `/api/radar/settings` | POST | Sets opt-in and/or the (encrypted) supporter key. |
|
||||
| `/api/radar/referrals` | GET | Returns `{ fixed, campaigns, tier }` from the local cache — see [Referral links](#referral-links-free-credits) below. |
|
||||
| `/api/radar/offers` | GET | Returns active offers from the verified local live cache; never returns the supporter key. |
|
||||
| `/api/radar/offers/sync` | POST | Triggers the server-side, live-key-only `syncRadarOffers()` pipeline. |
|
||||
| `/api/radar/intel` | GET | Returns verified local live Intel plus a supporter-recognition boolean; never an identity or key. |
|
||||
| `/api/radar/intel/sync` | POST | Triggers the server-side, live-key-only `syncRadarIntel()` pipeline. |
|
||||
| `/api/radar/status` | GET | Returns read-only local settings/cache status for catalog, referrals, offers, and Intel, without secrets. |
|
||||
| `/api/radar/sync-all` | POST | Runs all four server-side sync modules and returns a separate status for each feed. |
|
||||
| `/api/radar/local-model-state` | GET | Lists persisted overrides and tombstones for edit/restore controls. |
|
||||
| `/api/radar/local-model-state` | PATCH | Sets or clears the validated `displayName`/`enabled` override fields. |
|
||||
| `/api/radar/local-model-state` | PUT | Creates or removes a tombstone with `{ provider, modelId, tombstoned }`. |
|
||||
| `/api/radar/local-model-state` | DELETE | Clears editable override fields while preserving any tombstone. |
|
||||
|
||||
**Hard rule: these routes never proxy the feed service.** The browser only ever talks
|
||||
to the local OmniRoute server. The two modules that touch the Radar service are
|
||||
`src/lib/radar/sync.ts` (catalog) and `src/lib/radar/referralsSync.ts` (referrals); both
|
||||
always run server-side, never client-side. This keeps the feed URL and any supporter key
|
||||
out of client-facing network traffic entirely.
|
||||
to the local OmniRoute server. The four modules that touch the Radar service are
|
||||
`src/lib/radar/sync.ts` (catalog), `src/lib/radar/referralsSync.ts` (referrals), and
|
||||
`src/lib/radar/offersSync.ts` (offers) plus `src/lib/radar/intelSync.ts` (Intel); all run
|
||||
server-side, never client-side. This keeps
|
||||
the feed URL and any supporter key out of client-facing network traffic entirely.
|
||||
|
||||
All five routes return `404` when `RADAR_ENABLED` is off (see
|
||||
All Radar endpoints return `404` when `RADAR_ENABLED` is off (see
|
||||
[Flag](#flag-radar_enabled-default-off) above), and route error responses through
|
||||
`buildErrorBody()`/`sanitizeErrorMessage()` per the repo-wide error-sanitization rule
|
||||
(`docs/security/ERROR_SANITIZATION.md`).
|
||||
|
||||
### Authentication
|
||||
|
||||
All five routes require authentication via `isAuthenticated()`
|
||||
All Radar endpoints require authentication via `isAuthenticated()`
|
||||
(`src/shared/utils/apiAuth.ts`) — a dashboard session cookie or a management-scoped
|
||||
API key, the same gate that protects the rest of `/api/settings/*`. The flag-off
|
||||
`404` check always runs **before** the auth check, so an install with `RADAR_ENABLED`
|
||||
@@ -318,6 +481,58 @@ auth state — only the masked form and a `hasSupporterKey` boolean.
|
||||
|
||||
---
|
||||
|
||||
## Supporter offers
|
||||
|
||||
Offers use their own signed artifact, `GET /v1/offers/latest`, and never share the catalog or
|
||||
referrals cache. The server endpoint requires a valid live supporter Bearer key; there is no
|
||||
community fallback. `syncRadarOffers()` therefore stops before the network when the feature flag is
|
||||
off, the operator has not opted in, or no supporter key is configured.
|
||||
|
||||
After a successful GET, the client verifies the Ed25519 signature over the exact response bytes,
|
||||
validates `RadarOffersFeedSchema`, requires both the signed body and
|
||||
`x-omniroute-feed-tier` header to say `live`, enforces a strictly newer dotted version, and only then
|
||||
atomically replaces `radar_offers_cache` (migration `144_radar_offers_cache.sql`). The same 10 MB
|
||||
header-plus-stream cap used by the other feeds applies. Signature, schema, tier, replay, size, HTTP,
|
||||
and network failures all preserve the last verified cache.
|
||||
|
||||
The closed offer shape supports three comparable benefit types: percentage in basis points, credit
|
||||
in minor currency units, or trial days. A partner offer must include a same-kind public baseline and
|
||||
its benefit must be strictly greater; official offers have no partner baseline. URLs must be
|
||||
credential-free HTTPS. `getRadarOffers()` defensively revalidates the cached payload and filters
|
||||
expired entries on every local read; `/dashboard/radar/offers` filters expiry again before rendering,
|
||||
uses Portuguese text when available with English fallback, and labels partner offers explicitly.
|
||||
|
||||
The browser calls only local routes: it reads the masked settings snapshot, asks
|
||||
`POST /api/radar/offers/sync` to refresh server-side, then reads `GET /api/radar/offers`. Without a
|
||||
key it shows the existing contributor/support links instead of attempting a feed request. External
|
||||
offer links open in a new tab with `noopener noreferrer`. No `radar_offers` MCP tool is exposed in
|
||||
this release.
|
||||
|
||||
---
|
||||
|
||||
## Radar Intel, supporter badge, and CLI
|
||||
|
||||
Intel is a signed artifact at `GET /v1/intel/latest`. The closed `RadarIntelFeedSchema` accepts
|
||||
only Radar-owned ELO rankings derived by the private curator from confirmed comparisons and factual
|
||||
catalog age/count deltas derived from signed catalog snapshots. The methodology is fixed at initial
|
||||
rating 1000 and K=32. An empty ranking is valid when no comparison has been confirmed; the client
|
||||
never synthesizes one.
|
||||
|
||||
`syncRadarIntel()` applies the same server-side Bearer, 30-second timeout, 10 MiB streamed cap,
|
||||
exact-byte Ed25519 verification, strict schema, `live` body/header requirement, version floor, and
|
||||
last-good-cache preservation as offers. After a verified live snapshot is persisted, the client
|
||||
derives `radar:<sha256(supporter key)>`, stores only that one-way identity, and emits the dedicated
|
||||
`radar_supporter` recognition event. Its `radar-supporter` badge is idempotent and awards zero XP;
|
||||
it never updates leaderboards or reuses `token_share`. `/dashboard/radar/intel` renders the badge
|
||||
only from verified local cache metadata.
|
||||
|
||||
The CLI exposes `omniroute radar status` and `omniroute radar sync`. Both communicate only with the
|
||||
local OmniRoute API. `status` performs a read-only `GET /api/radar/status`; `sync` sends one
|
||||
`POST /api/radar/sync-all` and prints a result per feed. Neither command reads, accepts, or prints
|
||||
the supporter key, and neither contacts the Radar service directly.
|
||||
|
||||
---
|
||||
|
||||
## Referral links (free credits)
|
||||
|
||||
Referral links are served from a **standalone, always-current** feed —
|
||||
@@ -473,8 +688,9 @@ service without touching client code:
|
||||
|
||||
1. Serve a `GET /v1/catalog/latest` endpoint returning a JSON body that satisfies
|
||||
`RadarFeedSchema` (`src/lib/radar/feedSchema.ts`) — top-level `feed:
|
||||
"omniroute-radar"`, `schemaVersion: 1`, `version`, `tier`, `providers`, `models`,
|
||||
`quirks`, and `totals`.
|
||||
"omniroute-radar"`, `schemaVersion: 2`, `version`, `tier`, `providers`, `models`,
|
||||
`quirks`, and `totals`. Honor `x-omniroute-radar-schema: 2`; a transition-compatible server
|
||||
should default requests without it to a separately signed v1 artifact.
|
||||
2. Sign the exact response bytes with an Ed25519 key pair and return the base64
|
||||
signature in the `x-omniroute-feed-signature` response header.
|
||||
3. Set `RADAR_FEED_URL` to the new base URL and `RADAR_FEED_PUBKEY` to the matching
|
||||
@@ -498,11 +714,24 @@ instead of failing the rest of the page. To also offer referral links, serve
|
||||
(`src/lib/radar/referralsFeedSchema.ts`) and sign it with the same Ed25519 key pair as
|
||||
the catalog feed.
|
||||
|
||||
Supporter offers are another optional artifact. To serve them, implement
|
||||
`GET /v1/offers/latest` with the closed `RadarOffersFeedSchema`
|
||||
(`src/lib/radar/offersFeedSchema.ts`), require live entitlement, return
|
||||
`x-omniroute-feed-tier: live`, and sign the exact bytes with the same key. A fork that omits this
|
||||
endpoint keeps the catalog/referrals behavior unchanged; offer refresh fails non-destructively and
|
||||
the last verified local offer cache remains available.
|
||||
|
||||
Intel is optional in the same way. A self-hoster can serve `GET /v1/intel/latest` using
|
||||
`RadarIntelFeedSchema` (`src/lib/radar/intelFeedSchema.ts`), require live entitlement, return
|
||||
`x-omniroute-feed-tier: live`, and sign the exact bytes with the shared Ed25519 key. Omitting the
|
||||
endpoint leaves catalog, referrals, and offers unchanged; Intel refresh preserves any last verified
|
||||
local snapshot.
|
||||
|
||||
---
|
||||
|
||||
## Related docs
|
||||
|
||||
- [`docs/security/ERROR_SANITIZATION.md`](../security/ERROR_SANITIZATION.md) — the
|
||||
error-response pattern the five `/api/radar/*` routes follow.
|
||||
error-response pattern the `/api/radar/*` routes follow.
|
||||
- [`docs/reference/ENVIRONMENT.md`](../reference/ENVIRONMENT.md#27-radar-feed-self-hosting)
|
||||
— `RADAR_FEED_URL` / `RADAR_FEED_PUBKEY` reference.
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -4,10 +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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -21,7 +18,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -109,7 +106,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -131,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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -214,11 +211,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -269,7 +266,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -352,9 +349,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -397,7 +394,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -441,7 +438,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -485,7 +482,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
@@ -65,6 +65,7 @@ directly from anywhere — CI can only stage; only the owner's 2FA releases.
|
||||
as the default reflex (minutes, reversible); `npm unpublish` only inside the 72h/no-dependents
|
||||
window and never as the first move. Docker: never rewrite a version tag — rollback is
|
||||
repointing `latest` to the last good digest.
|
||||
|
||||
## Hotfix Fast-Lane (label `hotfix`)
|
||||
|
||||
A PR labeled `hotfix` skips the heavy CI matrix (9-shard E2E, coverage ratchet,
|
||||
@@ -276,6 +277,22 @@ Deploy skills use the light rsync flow — no `npm pack`, no `npm i -g`:
|
||||
- [ ] Open milestone for next version
|
||||
- [ ] If critical: pin discussion or post in `news.json` for in-app banner
|
||||
|
||||
### Radar public-launch gate
|
||||
|
||||
The Radar announcement is intentionally committed with `active: false`. Activation is a separate
|
||||
change after every item below is evidenced:
|
||||
|
||||
- [ ] All stacked Radar PRs are merged and the release-tip CI is green
|
||||
- [ ] Deploy and smoke the OSS Radar routes with `RADAR_ENABLED` still off by default
|
||||
- [ ] Smoke `GET /planos`, `/termos`, `/privacidade`, and `/reembolso` on the named Radar host
|
||||
- [ ] Record operator identity/contact/address and owner-approved legal review in the private service
|
||||
- [ ] Exercise Stripe Checkout and the signed webhook in test mode only
|
||||
- [ ] Exercise one encrypted transactional-email delivery with the approved sender/domain
|
||||
- [ ] Prove backup restore and one supervised, budget-capped research run
|
||||
- [ ] Approve the BRL/PIX review policy before accepting donation evidence
|
||||
- [ ] Enable public Checkout only after the preceding gates, then activate the new `news.json` ID
|
||||
- [ ] Verify the Home banner uses localized copy and a new ID reappears after an older ID is dismissed
|
||||
|
||||
## Embedded Services smoke (v3.8.4+)
|
||||
|
||||
Before shipping any release that includes embedded services changes, verify:
|
||||
|
||||
@@ -1352,17 +1352,24 @@ that should be able to run the docs translator.
|
||||
Optional add-on gated by the RADAR_ENABLED feature flag (default off — a feature
|
||||
flag toggled via Settings/DB, not an env var; see
|
||||
[docs/frameworks/RADAR.md](../frameworks/RADAR.md#flag-radar_enabled-default-off)).
|
||||
The four variables below are optional overrides used only to point the client at a
|
||||
self-hosted or forked feed / supporter-key flow instead of the default OmniRoute
|
||||
Radar service. See [docs/frameworks/RADAR.md](../frameworks/RADAR.md) for the full
|
||||
module doc.
|
||||
The first four variables below are optional overrides for a self-hosted or forked feed and
|
||||
supporter-key flows. The fifth, `RADAR_ADMIN_URL`, is a separate default-free link to the owner's
|
||||
private operations panel. See [docs/frameworks/RADAR.md](../frameworks/RADAR.md) for the full
|
||||
module doc and its
|
||||
[end-to-end activation and guided-setup sequence](../frameworks/RADAR.md#end-to-end-activation-and-guided-setup).
|
||||
|
||||
The generic Home/Changelog announcement reader is not configured by an environment
|
||||
variable and does not depend on the RADAR_ENABLED feature flag. It reads the public repository
|
||||
`news.json` URL declared in `src/shared/utils/releaseNotes.ts` by
|
||||
GET only; dismissal IDs remain in browser local storage.
|
||||
|
||||
| Variable | Default | Source File | Description |
|
||||
| -------------------------------- | --------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------ |
|
||||
| `RADAR_FEED_URL` | `https://radar.omniroute.online` | `src/lib/radar/sync.ts` | Base URL of the Radar feed service. Override to point at a self-hosted or forked feed. |
|
||||
| `RADAR_FEED_URL` | `https://radar.omniroute.online` | `src/lib/radar/{sync,referralsSync,offersSync,intelSync}.ts` | Base URL shared by the separately signed catalog, referrals, supporter-offers, and Intel feeds. Override to point at a self-hosted or forked service. |
|
||||
| `RADAR_FEED_PUBKEY` | _(pinned default key)_ | `src/lib/radar/pinnedKeys.ts` | Ed25519 public key (base64-DER SPKI or PEM) used to verify feed signatures from a custom feed. |
|
||||
| `RADAR_CONTRIBUTOR_CLAIM_URL` | `https://radar.omniroute.online/auth/github` | `src/lib/radar/links.ts` | URL the "I'm a contributor" dashboard button opens (GitHub OAuth supporter-key claim flow). |
|
||||
| `RADAR_SUPPORTER_PLANS_URL` | `https://radar.omniroute.online/planos` | `src/lib/radar/links.ts` | URL the "Support the project" dashboard button opens (payment/plans page). |
|
||||
| `RADAR_ADMIN_URL` | _(unset)_ | `src/lib/radar/links.ts` | Owner-only private operations-panel link. HTTPS is required except for an HTTP loopback SSH forward; unset or invalid values create no navigation item. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
24
llm.txt
24
llm.txt
@@ -1,6 +1,6 @@
|
||||
# OmniRoute
|
||||
|
||||
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (105 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 339 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -14,7 +14,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
|
||||
- **Runtime:** Node.js `>=22.0.0 <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, 145 migrations)
|
||||
- **Database:** SQLite via better-sqlite3 (local, zero-config, 148 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
|
||||
@@ -102,7 +102,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ │ └── streaming.ts # SSE streaming for A2A
|
||||
│ │ ├── acp/ # Agent Communication Protocol registry and manager
|
||||
│ │ ├── compliance/ # Compliance policy engine
|
||||
│ │ ├── db/ # SQLite database layer (99 modules + migrations)
|
||||
│ │ ├── db/ # SQLite database layer (117 modules + migrations)
|
||||
│ │ │ ├── core.ts # Database initialization, connection, schema
|
||||
│ │ │ ├── providers.ts # Provider connection CRUD
|
||||
│ │ │ ├── models.ts # Model catalog management
|
||||
@@ -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/ # 117 versioned SQL migration files
|
||||
│ │ │ └── migrations/ # 148 versioned SQL migration files
|
||||
│ │ ├── evals/ # Eval runner and scheduler
|
||||
│ │ ├── memory/ # Persistent conversational memory
|
||||
│ │ │ ├── extraction.ts # Memory extraction from conversations
|
||||
@@ -207,11 +207,11 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ │ ├── moderations.ts # Content moderation
|
||||
│ │ ├── rerank.ts # Reranking API
|
||||
│ │ └── search.ts # Web search API
|
||||
│ ├── mcp-server/ # Built-in MCP server (105 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ ├── mcp-server/ # Built-in MCP server (109 tools, 3 transports: stdio/SSE/streamable-HTTP)
|
||||
│ │ ├── server.ts # MCP server core (tool registration, scope enforcement)
|
||||
│ │ ├── tools/ # Tool implementations (advancedTools, memoryTools, skillTools)
|
||||
│ │ ├── schemas/ # Zod input schemas (tools, audit, a2a)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (31 scopes)
|
||||
│ │ ├── scopeEnforcement.ts # Scope-based access control (33 scopes)
|
||||
│ │ ├── audit.ts # Tool call audit logging
|
||||
│ │ ├── runtimeHeartbeat.ts # MCP runtime heartbeat
|
||||
│ │ └── httpTransport.ts # HTTP transport handler
|
||||
@@ -262,7 +262,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
│ ├── i18n/ # 43-language translated docs
|
||||
│ ├── architecture/ # ARCHITECTURE.md, CODEBASE_DOCUMENTATION.md, REPOSITORY_MAP.md, AUTHZ_GUIDE.md, RESILIENCE_GUIDE.md, QUALITY_GATES.md
|
||||
│ ├── reference/ # API_REFERENCE.md, PROVIDER_REFERENCE.md, CLI-TOOLS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (105 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── frameworks/ # MCP-SERVER.md (109 tools), A2A-SERVER.md, SKILLS.md, MEMORY.md, CLOUD_AGENT.md, EVALS.md, WEBHOOKS.md
|
||||
│ ├── routing/ # AUTO-COMBO.md (14-factor scoring), REASONING_REPLAY.md
|
||||
│ ├── security/ # GUARDRAILS.md, COMPLIANCE.md, STEALTH_GUIDE.md, PUBLIC_CREDS.md, ERROR_SANITIZATION.md
|
||||
│ ├── guides/ # USER_GUIDE.md, TROUBLESHOOTING.md, ELECTRON_GUIDE.md, I18N.md
|
||||
@@ -345,9 +345,9 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
|
||||
- **A2A** — Agent-to-Agent v0.3 protocol (JSON-RPC 2.0, 6 skills: smart-routing, quota-management, provider-discovery, cost-analysis, health-report, list-capabilities)
|
||||
- **ACP** — Agent Communication Protocol registry and manager
|
||||
|
||||
### MCP Server (105 Tools)
|
||||
### MCP Server (109 Tools)
|
||||
|
||||
105 tools across modules: **43 base** (health, combos, quotas, routing, cost, models, cache,
|
||||
109 tools across modules: **44 canonical** (health, combos, quotas, routing, cost, models, cache,
|
||||
diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool**, **notion**,
|
||||
**obsidian**, **localCorpus**, **gamification**, and **plugin** modules. Full per-tool inventory:
|
||||
`docs/frameworks/MCP-SERVER.md`.
|
||||
@@ -390,7 +390,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 99 `src/lib/db/` modules with 117 SQL migrations.
|
||||
9. **DB architecture:** `localDb.ts` is a re-export layer only — real logic lives in 117 `src/lib/db/` modules with 148 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`.
|
||||
|
||||
@@ -434,7 +434,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 (117 domain-specific files, 145 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 (117 domain-specific files, 148 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.
|
||||
|
||||
@@ -478,7 +478,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool
|
||||
- **339-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
|
||||
- **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay`
|
||||
- **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown
|
||||
- **MCP server expanded to 105 tools / 31 scopes** (base + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)
|
||||
- **Cloud Agents** (Codex Cloud, Devin, Jules), **Guardrails**, **Evals**, **Webhooks**, **Compliance** frameworks
|
||||
- **Embedded services** manager (install/start/stop bundled services from the dashboard)
|
||||
- **Prompt compression** (RTK + Caveman codecs) saving up to ~95% tokens on eligible traffic
|
||||
|
||||
47
news.json
47
news.json
@@ -1,8 +1,43 @@
|
||||
{
|
||||
"active": false,
|
||||
"title": "Novidade no Omniverse",
|
||||
"message": "Está lançado hoje o tOmni, o terminal interativo múltiplo para Agentes de AI! Experimente a nova interface focada em produtividade para desenvolvedores.",
|
||||
"link": "https://github.com/diegosouzapw/tOmni",
|
||||
"linkLabel": "Conhecer o tOmni",
|
||||
"icon": "campaign"
|
||||
"schemaVersion": 2,
|
||||
"items": [
|
||||
{
|
||||
"id": "radar-launch-2026-08",
|
||||
"active": false,
|
||||
"publishedAt": "2026-08-09T00:00:00.000Z",
|
||||
"text": {
|
||||
"en": {
|
||||
"title": "OmniRoute Radar",
|
||||
"message": "An opt-in, GET-only free-model catalog overlay with no telemetry from the OmniRoute client.",
|
||||
"linkLabel": "Learn about Radar"
|
||||
},
|
||||
"pt-BR": {
|
||||
"title": "OmniRoute Radar",
|
||||
"message": "Um catálogo opcional de modelos gratuitos, somente GET e sem telemetria enviada pelo cliente OmniRoute.",
|
||||
"linkLabel": "Conheça o Radar"
|
||||
}
|
||||
},
|
||||
"link": "https://radar.omniroute.online/planos",
|
||||
"icon": "radar"
|
||||
},
|
||||
{
|
||||
"id": "tomni-launch-2026-07",
|
||||
"active": false,
|
||||
"publishedAt": "2026-07-01T00:00:00.000Z",
|
||||
"text": {
|
||||
"en": {
|
||||
"title": "New in the Omniverse",
|
||||
"message": "tOmni is an interactive multi-agent terminal focused on developer productivity.",
|
||||
"linkLabel": "Meet tOmni"
|
||||
},
|
||||
"pt-BR": {
|
||||
"title": "Novidade no Omniverse",
|
||||
"message": "O tOmni é um terminal interativo para múltiplos agentes, focado na produtividade de desenvolvedores.",
|
||||
"linkLabel": "Conhecer o tOmni"
|
||||
}
|
||||
},
|
||||
"link": "https://github.com/diegosouzapw/tOmni",
|
||||
"icon": "campaign"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# OmniRoute MCP Server
|
||||
|
||||
> **Model Context Protocol server** that exposes OmniRoute's gateway intelligence as **107 tools** for AI agents.
|
||||
> **Model Context Protocol server** that exposes OmniRoute's gateway intelligence as **109 tools** for AI agents.
|
||||
>
|
||||
> **Source of truth for the full tool catalog and REST surface:** [`docs/frameworks/MCP-SERVER.md`](../../docs/frameworks/MCP-SERVER.md). This README focuses on architecture, configuration, and integration examples; the catalog below is a summary subset.
|
||||
|
||||
@@ -20,7 +20,7 @@ The MCP Server allows any AI agent (Claude Desktop, Cursor, VS Code Copilot, cus
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ OmniRoute MCP Server │
|
||||
│ ┌──────────────┐ ┌─────────────────┐ ┌────────────────────┐ │
|
||||
│ │ Scope │ │ 107 MCP Tools │ │ Audit Logger │ │
|
||||
│ │ Scope │ │ 109 MCP Tools │ │ Audit Logger │ │
|
||||
│ │ Enforcement │──│ (core + memory │──│ (SHA-256/SQLite) │ │
|
||||
│ │ │ │ + skills + …) │ │ │ │
|
||||
│ └──────────────┘ └────────┬────────┘ └────────────────────┘ │
|
||||
@@ -120,18 +120,23 @@ omniroute --mcp
|
||||
|
||||
## Tool Reference
|
||||
|
||||
### Phase 1: Essential Tools (8)
|
||||
### Phase 1: Essential Tools (13)
|
||||
|
||||
| # | Tool | Scopes | Description |
|
||||
| --- | ------------------------------- | --------------------- | -------------------------------------------------------------------------- |
|
||||
| 1 | `omniroute_get_health` | `read:health` | Gateway health, uptime, memory, circuit breakers, rate limits, cache stats |
|
||||
| 2 | `omniroute_list_combos` | `read:combos` | List all combos (model chains) with strategies and optional metrics |
|
||||
| 3 | `omniroute_get_combo_metrics` | `read:combos` | Performance metrics for a specific combo |
|
||||
| 4 | `omniroute_switch_combo` | `write:combos` | Activate or deactivate a combo for routing |
|
||||
| 5 | `omniroute_check_quota` | `read:quota` | Remaining API quota per provider with token health status |
|
||||
| 6 | `omniroute_route_request` | `execute:completions` | Send a chat completion through intelligent routing |
|
||||
| 7 | `omniroute_cost_report` | `read:usage` | Cost report by period (session/day/week/month) with per-provider breakdown |
|
||||
| 8 | `omniroute_list_models_catalog` | `read:models` | List all available models across providers with capabilities and pricing |
|
||||
| 1 | `omniroute_tool_search` | `read:tools` | Discover tools from the registered MCP catalog |
|
||||
| 2 | `omniroute_get_health` | `read:health` | Gateway health, uptime, memory, circuit breakers, rate limits, cache stats |
|
||||
| 3 | `omniroute_list_combos` | `read:combos` | List all combos (model chains) with strategies and optional metrics |
|
||||
| 4 | `omniroute_get_combo_metrics` | `read:combos` | Performance metrics for a specific combo |
|
||||
| 5 | `omniroute_switch_combo` | `write:combos` | Activate or deactivate a combo for routing |
|
||||
| 6 | `omniroute_create_combo` | `write:combos` | Create a validated combo through the existing combo API |
|
||||
| 7 | `omniroute_check_quota` | `read:quota` | Remaining API quota per provider with token health status |
|
||||
| 8 | `omniroute_route_request` | `execute:completions` | Send a chat completion through intelligent routing |
|
||||
| 9 | `omniroute_cost_report` | `read:usage` | Cost report by period (session/day/week/month) with per-provider breakdown |
|
||||
| 10 | `omniroute_list_models_catalog` | `read:models` | List all available models across providers with capabilities and pricing |
|
||||
| 11 | `omniroute_radar_catalog` | `read:radar` | Read the local signed Radar catalog with provider/family filters |
|
||||
| 12 | `omniroute_web_search` | `execute:search` | Search the web through configured search providers |
|
||||
| 13 | `omniroute_web_fetch` | `execute:search` | Fetch web content through configured fetch providers |
|
||||
|
||||
### Phase 2: Advanced Tools (8)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Unit tests for MCP Essential Tools (Phase 1)
|
||||
*
|
||||
* Tests all 10 essential tool handlers via the tool handler functions.
|
||||
* Tests the essential tool handlers via the tool handler functions.
|
||||
* The omniroute_web_search tests use InMemoryTransport + Client to exercise
|
||||
* the actual registered handler (not mockFetch directly).
|
||||
*/
|
||||
@@ -22,10 +22,10 @@ describe("MCP Essential Tools", () => {
|
||||
});
|
||||
|
||||
describe("Tool schema validation", () => {
|
||||
it("should have exactly 12 essential tools (includes web_search + web_fetch + tool_search)", () => {
|
||||
// 11 -> 12: #8925 shipped omniroute_create_combo as a phase-1 tool.
|
||||
it("should have exactly 13 essential tools (including Radar catalog)", () => {
|
||||
// 12 -> 13: F3 shipped omniroute_radar_catalog as a phase-1 read-only tool.
|
||||
const schemas = MCP_ESSENTIAL_TOOLS;
|
||||
expect(schemas).toHaveLength(12);
|
||||
expect(schemas).toHaveLength(13);
|
||||
});
|
||||
|
||||
it("all tools should have omniroute_ prefix", () => {
|
||||
|
||||
151
open-sse/mcp-server/__tests__/radarCatalogTool.test.ts
Normal file
151
open-sse/mcp-server/__tests__/radarCatalogTool.test.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
||||
|
||||
import { MCP_SCOPE_LIST, MCP_TOOL_SCOPES } from "../../../src/shared/constants/mcpScopes.ts";
|
||||
import { evaluateToolScopes } from "../scopeEnforcement.ts";
|
||||
import { getMcpRadarCatalog } from "../radarCatalog.ts";
|
||||
import { MCP_ESSENTIAL_TOOLS, MCP_TOOL_MAP } from "../schemas/tools.ts";
|
||||
import { createMcpServer } from "../server.ts";
|
||||
|
||||
vi.mock("../audit.ts", () => ({
|
||||
logToolCall: vi.fn().mockResolvedValue(undefined),
|
||||
}));
|
||||
|
||||
const catalog = {
|
||||
entries: [
|
||||
{
|
||||
provider: "groq",
|
||||
modelId: "llama",
|
||||
displayName: "Llama on Groq",
|
||||
familyId: "llama-family",
|
||||
monthlyTokens: 200,
|
||||
creditTokens: 0,
|
||||
freeType: "recurring-daily",
|
||||
poolKey: null,
|
||||
tos: "ok",
|
||||
enabled: true,
|
||||
origin: "radar",
|
||||
capabilities: { tools: true, vision: false, thinking: false },
|
||||
limits: { rpm: 30, rpd: null, tpm: null, tpd: null },
|
||||
setup: { keyUrl: "https://secret.example/key", steps: ["do not expose"] },
|
||||
},
|
||||
{
|
||||
provider: "cerebras",
|
||||
modelId: "llama",
|
||||
displayName: "Llama on Cerebras",
|
||||
familyId: "llama-family",
|
||||
monthlyTokens: 300,
|
||||
creditTokens: 0,
|
||||
freeType: "recurring-daily",
|
||||
poolKey: null,
|
||||
tos: "ok",
|
||||
enabled: false,
|
||||
disabledBy: "radar",
|
||||
origin: "radar",
|
||||
capabilities: { tools: true, vision: false, thinking: true },
|
||||
limits: { rpm: null, rpd: 100, tpm: null, tpd: null },
|
||||
},
|
||||
],
|
||||
meta: { version: "2026.08.08.1", tier: "community", fetchedAt: "2026-08-08T20:00:00Z" },
|
||||
};
|
||||
|
||||
describe("omniroute_radar_catalog", () => {
|
||||
it("is a phase-1 read-only registry tool with the dedicated Radar scope", () => {
|
||||
const definition = MCP_TOOL_MAP.omniroute_radar_catalog;
|
||||
expect(definition).toBeDefined();
|
||||
expect(definition.phase).toBe(1);
|
||||
expect(definition.scopes).toEqual(["read:radar"]);
|
||||
expect(definition.auditLevel).toBe("none");
|
||||
expect(definition.sourceEndpoints).toEqual(["/api/radar/catalog"]);
|
||||
expect(MCP_ESSENTIAL_TOOLS).toContain(definition);
|
||||
expect(MCP_SCOPE_LIST).toContain("read:radar");
|
||||
expect(MCP_TOOL_SCOPES.omniroute_radar_catalog).toEqual(["read:radar"]);
|
||||
});
|
||||
|
||||
it("reads only the local catalog and returns a closed filtered projection", async () => {
|
||||
const fetchJson = vi.fn().mockResolvedValue(catalog);
|
||||
const result = await getMcpRadarCatalog(
|
||||
{ provider: "groq", familyId: "llama-family", enabledOnly: true },
|
||||
{ fetchJson }
|
||||
);
|
||||
|
||||
expect(fetchJson).toHaveBeenCalledOnce();
|
||||
expect(fetchJson).toHaveBeenCalledWith("/api/radar/catalog");
|
||||
expect(result.models).toHaveLength(1);
|
||||
expect(result.models[0]).toEqual({
|
||||
provider: "groq",
|
||||
modelId: "llama",
|
||||
displayName: "Llama on Groq",
|
||||
familyId: "llama-family",
|
||||
quota: {
|
||||
monthlyTokens: 200,
|
||||
creditTokens: 0,
|
||||
freeType: "recurring-daily",
|
||||
limits: { rpm: 30, rpd: null, tpm: null, tpd: null },
|
||||
},
|
||||
capabilities: { tools: true, vision: false, thinking: false },
|
||||
enabled: true,
|
||||
origin: "radar",
|
||||
disabledBy: null,
|
||||
});
|
||||
expect(JSON.stringify(result)).not.toContain("secret.example");
|
||||
expect(JSON.stringify(result)).not.toContain("setup");
|
||||
});
|
||||
|
||||
it("defaults enabledOnly to true and includes disabled models only when explicitly requested", async () => {
|
||||
const fetchJson = vi.fn().mockResolvedValue(catalog);
|
||||
expect((await getMcpRadarCatalog({}, { fetchJson })).models).toHaveLength(1);
|
||||
expect((await getMcpRadarCatalog({ enabledOnly: false }, { fetchJson })).models).toHaveLength(
|
||||
2
|
||||
);
|
||||
});
|
||||
|
||||
it("allows read:radar and read:* but denies a missing scope when enforcement is active", () => {
|
||||
expect(evaluateToolScopes("omniroute_radar_catalog", ["read:radar"], true).allowed).toBe(true);
|
||||
expect(evaluateToolScopes("omniroute_radar_catalog", ["read:*"], true).allowed).toBe(true);
|
||||
expect(evaluateToolScopes("omniroute_radar_catalog", [], true)).toMatchObject({
|
||||
allowed: false,
|
||||
reason: "missing_scopes",
|
||||
missing: ["read:radar"],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("omniroute_radar_catalog MCP dispatch", () => {
|
||||
const mockFetch = vi.fn();
|
||||
let client: Client;
|
||||
|
||||
beforeEach(async () => {
|
||||
mockFetch.mockReset();
|
||||
vi.stubGlobal("fetch", mockFetch);
|
||||
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
||||
const server = createMcpServer();
|
||||
await server.connect(serverTransport);
|
||||
client = new Client({ name: "radar-catalog-test", version: "1.0.0" });
|
||||
await client.connect(clientTransport);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await client.close();
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it("registers and dispatches a real read without sync or write", async () => {
|
||||
mockFetch.mockResolvedValueOnce({ ok: true, json: async () => catalog });
|
||||
|
||||
const listed = await client.listTools();
|
||||
expect(listed.tools.some((tool) => tool.name === "omniroute_radar_catalog")).toBe(true);
|
||||
|
||||
const result = await client.callTool({
|
||||
name: "omniroute_radar_catalog",
|
||||
arguments: { enabledOnly: false },
|
||||
});
|
||||
expect(result.isError).toBeFalsy();
|
||||
expect(mockFetch).toHaveBeenCalledOnce();
|
||||
expect(mockFetch.mock.calls[0][0]).toContain("/api/radar/catalog");
|
||||
expect(mockFetch.mock.calls[0][1]).not.toMatchObject({ method: "POST" });
|
||||
const body = JSON.parse((result.content[0] as { text: string }).text);
|
||||
expect(body.models).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
170
open-sse/mcp-server/radarCatalog.ts
Normal file
170
open-sse/mcp-server/radarCatalog.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
|
||||
import { logToolCall } from "./audit.ts";
|
||||
import { radarCatalogInput, radarCatalogOutput } from "./schemas/radarCatalog.ts";
|
||||
import type { McpToolExtraLike } from "./scopeEnforcement.ts";
|
||||
import type { TextToolResult } from "./toolResult.ts";
|
||||
import { sanitizeErrorMessage } from "../utils/error.ts";
|
||||
|
||||
type JsonRecord = Record<string, unknown>;
|
||||
|
||||
type ScopeEnforcer = (
|
||||
toolName: string,
|
||||
handler: (args: unknown, extra?: McpToolExtraLike) => Promise<TextToolResult>,
|
||||
toolScopes?: readonly string[]
|
||||
) => (args: unknown, extra?: McpToolExtraLike) => Promise<TextToolResult>;
|
||||
|
||||
export interface McpRadarCatalogArgs {
|
||||
provider?: string;
|
||||
familyId?: string;
|
||||
enabledOnly?: boolean;
|
||||
}
|
||||
|
||||
interface McpRadarCatalogDeps {
|
||||
fetchJson?: (path: string) => Promise<unknown>;
|
||||
}
|
||||
|
||||
function record(value: unknown): JsonRecord {
|
||||
return value !== null && typeof value === "object" && !Array.isArray(value)
|
||||
? (value as JsonRecord)
|
||||
: {};
|
||||
}
|
||||
|
||||
function text(value: unknown, fallback = ""): string {
|
||||
return typeof value === "string" ? value : fallback;
|
||||
}
|
||||
|
||||
function number(value: unknown): number {
|
||||
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
|
||||
}
|
||||
|
||||
function nullableNumber(value: unknown): number | null {
|
||||
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
||||
}
|
||||
|
||||
function normalizeMeta(
|
||||
value: unknown
|
||||
): { version: string; tier: string; fetchedAt: string } | null {
|
||||
const meta = record(value);
|
||||
if (
|
||||
typeof meta.version !== "string" ||
|
||||
typeof meta.tier !== "string" ||
|
||||
typeof meta.fetchedAt !== "string"
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return { version: meta.version, tier: meta.tier, fetchedAt: meta.fetchedAt };
|
||||
}
|
||||
|
||||
function normalizeEntry(value: unknown) {
|
||||
const entry = record(value);
|
||||
const provider = text(entry.provider).trim();
|
||||
const modelId = text(entry.modelId).trim();
|
||||
if (!provider || !modelId) return null;
|
||||
|
||||
const capabilities = record(entry.capabilities);
|
||||
const limits = record(entry.limits);
|
||||
const origin =
|
||||
entry.origin === "radar" || entry.origin === "local" ? entry.origin : ("baseline" as const);
|
||||
return {
|
||||
provider,
|
||||
modelId,
|
||||
displayName: text(entry.displayName, modelId),
|
||||
familyId: typeof entry.familyId === "string" ? entry.familyId : null,
|
||||
quota: {
|
||||
monthlyTokens: number(entry.monthlyTokens),
|
||||
creditTokens: number(entry.creditTokens),
|
||||
freeType: text(entry.freeType, "unknown"),
|
||||
limits:
|
||||
Object.keys(limits).length > 0
|
||||
? {
|
||||
rpm: nullableNumber(limits.rpm),
|
||||
rpd: nullableNumber(limits.rpd),
|
||||
tpm: nullableNumber(limits.tpm),
|
||||
tpd: nullableNumber(limits.tpd),
|
||||
}
|
||||
: null,
|
||||
},
|
||||
capabilities:
|
||||
Object.keys(capabilities).length > 0
|
||||
? {
|
||||
tools: capabilities.tools === true,
|
||||
vision: capabilities.vision === true,
|
||||
thinking: capabilities.thinking === true,
|
||||
}
|
||||
: null,
|
||||
enabled: entry.enabled !== false,
|
||||
origin,
|
||||
disabledBy: entry.disabledBy === "radar" ? ("radar" as const) : null,
|
||||
};
|
||||
}
|
||||
|
||||
function compareEntries(
|
||||
left: NonNullable<ReturnType<typeof normalizeEntry>>,
|
||||
right: NonNullable<ReturnType<typeof normalizeEntry>>
|
||||
): number {
|
||||
return left.provider.localeCompare(right.provider) || left.modelId.localeCompare(right.modelId);
|
||||
}
|
||||
|
||||
/** Read and project the local Radar catalog without exposing setup or secret-bearing state. */
|
||||
export async function getMcpRadarCatalog(
|
||||
args: McpRadarCatalogArgs,
|
||||
deps: McpRadarCatalogDeps = {}
|
||||
) {
|
||||
const fetchJson =
|
||||
deps.fetchJson ??
|
||||
((path: string) => import("./server.ts").then((module) => module.omniRouteFetch(path)));
|
||||
const raw = record(await fetchJson("/api/radar/catalog"));
|
||||
const providerFilter = args.provider?.trim().toLowerCase();
|
||||
const familyFilter = args.familyId?.trim().toLowerCase();
|
||||
const enabledOnly = args.enabledOnly !== false;
|
||||
const entries = Array.isArray(raw.entries) ? raw.entries : [];
|
||||
const models = entries
|
||||
.map(normalizeEntry)
|
||||
.filter((entry): entry is NonNullable<typeof entry> => entry !== null)
|
||||
.filter((entry) => !enabledOnly || entry.enabled)
|
||||
.filter((entry) => !providerFilter || entry.provider.toLowerCase() === providerFilter)
|
||||
.filter((entry) => !familyFilter || entry.familyId?.toLowerCase() === familyFilter)
|
||||
.sort(compareEntries);
|
||||
|
||||
return { meta: normalizeMeta(raw.meta), models };
|
||||
}
|
||||
|
||||
async function handleRadarCatalog(args: {
|
||||
provider?: string;
|
||||
familyId?: string;
|
||||
enabledOnly: boolean;
|
||||
}): Promise<TextToolResult> {
|
||||
const start = Date.now();
|
||||
try {
|
||||
const result = radarCatalogOutput.parse(await getMcpRadarCatalog(args));
|
||||
await logToolCall(
|
||||
"omniroute_radar_catalog",
|
||||
args,
|
||||
{ modelCount: result.models.length },
|
||||
Date.now() - start,
|
||||
true
|
||||
);
|
||||
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
||||
} catch (error) {
|
||||
const message = sanitizeErrorMessage(error) || "Failed to read Radar catalog";
|
||||
await logToolCall("omniroute_radar_catalog", args, null, Date.now() - start, false, message);
|
||||
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
||||
}
|
||||
}
|
||||
|
||||
export function registerRadarCatalogTool(
|
||||
server: McpServer,
|
||||
withScopeEnforcement: ScopeEnforcer
|
||||
): void {
|
||||
server.registerTool(
|
||||
"omniroute_radar_catalog",
|
||||
{
|
||||
description: "Reads the local signed Radar catalog with optional provider and family filters",
|
||||
inputSchema: radarCatalogInput,
|
||||
},
|
||||
withScopeEnforcement("omniroute_radar_catalog", (args) =>
|
||||
handleRadarCatalog(radarCatalogInput.parse(args))
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -91,6 +91,8 @@ export {
|
||||
ccrStatsTool,
|
||||
} from "./tools.ts";
|
||||
|
||||
export { radarCatalogInput, radarCatalogOutput, radarCatalogTool } from "./radarCatalog.ts";
|
||||
|
||||
// A2A schemas
|
||||
export {
|
||||
AgentCardSchema,
|
||||
|
||||
65
open-sse/mcp-server/schemas/radarCatalog.ts
Normal file
65
open-sse/mcp-server/schemas/radarCatalog.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import type { McpToolDefinition } from "./toolDefinition.ts";
|
||||
|
||||
export const radarCatalogInput = z.object({
|
||||
provider: z.string().trim().min(1).max(100).optional().describe("Filter by provider id"),
|
||||
familyId: z.string().trim().min(1).max(120).optional().describe("Filter by curated family id"),
|
||||
enabledOnly: z.boolean().default(true).describe("Exclude models disabled by the Radar feed"),
|
||||
});
|
||||
|
||||
const radarLimitOutput = z.object({
|
||||
rpm: z.number().nullable(),
|
||||
rpd: z.number().nullable(),
|
||||
tpm: z.number().nullable(),
|
||||
tpd: z.number().nullable(),
|
||||
});
|
||||
|
||||
export const radarCatalogOutput = z.object({
|
||||
meta: z
|
||||
.object({
|
||||
version: z.string(),
|
||||
tier: z.string(),
|
||||
fetchedAt: z.string(),
|
||||
})
|
||||
.nullable(),
|
||||
models: z.array(
|
||||
z.object({
|
||||
provider: z.string(),
|
||||
modelId: z.string(),
|
||||
displayName: z.string(),
|
||||
familyId: z.string().nullable(),
|
||||
quota: z.object({
|
||||
monthlyTokens: z.number(),
|
||||
creditTokens: z.number(),
|
||||
freeType: z.string(),
|
||||
limits: radarLimitOutput.nullable(),
|
||||
}),
|
||||
capabilities: z
|
||||
.object({
|
||||
tools: z.boolean(),
|
||||
vision: z.boolean(),
|
||||
thinking: z.boolean(),
|
||||
})
|
||||
.nullable(),
|
||||
enabled: z.boolean(),
|
||||
origin: z.enum(["baseline", "radar", "local"]),
|
||||
disabledBy: z.literal("radar").nullable(),
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
export const radarCatalogTool: McpToolDefinition<
|
||||
typeof radarCatalogInput,
|
||||
typeof radarCatalogOutput
|
||||
> = {
|
||||
name: "omniroute_radar_catalog",
|
||||
description:
|
||||
"Reads the local signed Radar catalog with optional provider and curated-family filters. Never syncs or writes data.",
|
||||
inputSchema: radarCatalogInput,
|
||||
outputSchema: radarCatalogOutput,
|
||||
scopes: ["read:radar"],
|
||||
auditLevel: "none",
|
||||
phase: 1,
|
||||
sourceEndpoints: ["/api/radar/catalog"],
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* MCP Tool Schemas — Contracts for all 23 core and advanced OmniRoute MCP tools.
|
||||
* MCP Tool Schemas — Contracts for the canonical OmniRoute MCP tools.
|
||||
*
|
||||
* Defines input/output Zod schemas, descriptions, scopes, and audit levels
|
||||
* for both essential (Phase 1) and advanced (Phase 2) MCP tools.
|
||||
@@ -13,11 +13,11 @@ import { z } from "zod";
|
||||
import { toolSearchTool } from "./toolSearch.ts";
|
||||
import { pickFastestModelTool } from "./pickFastestModel.ts";
|
||||
import { CCR_MCP_TOOLS } from "./ccrTools.ts";
|
||||
import { radarCatalogTool } from "./radarCatalog.ts";
|
||||
import {
|
||||
AUTO_ROUTING_STRATEGY_VALUES,
|
||||
ROUTING_STRATEGY_VALUES,
|
||||
} from "../../../src/shared/constants/routingStrategies.ts";
|
||||
|
||||
// ============ Shared Types ============
|
||||
// AuditLevel + McpToolDefinition live in the leaf ./toolDefinition.ts so that
|
||||
// toolSearch.ts can import the type without forming a tools.ts ↔ toolSearch.ts cycle.
|
||||
@@ -26,8 +26,7 @@ export type { AuditLevel, McpToolDefinition } from "./toolDefinition.ts";
|
||||
import type { McpToolDefinition } from "./toolDefinition.ts";
|
||||
export { pickFastestModelInput, pickFastestModelOutput } from "./pickFastestModel.ts";
|
||||
export * from "./ccrTools.ts";
|
||||
|
||||
// ============ Phase 1: Essential Tools (8) ============
|
||||
// ============ Phase 1: Essential Tools ============
|
||||
|
||||
// --- Tool 1: omniroute_get_health ---
|
||||
export const getHealthInput = z.object({}).describe("No parameters required");
|
||||
@@ -440,7 +439,7 @@ export const listModelsCatalogTool: McpToolDefinition<
|
||||
sourceEndpoints: ["/api/models/catalog", "/v1/models"],
|
||||
};
|
||||
|
||||
// --- Tool 9: omniroute_web_search ---
|
||||
// --- Tool 10: omniroute_web_search ---
|
||||
export const webSearchInput = z.object({
|
||||
query: z
|
||||
.string()
|
||||
@@ -1519,6 +1518,7 @@ export const MCP_TOOLS = [
|
||||
routeRequestTool,
|
||||
costReportTool,
|
||||
listModelsCatalogTool,
|
||||
radarCatalogTool,
|
||||
webSearchTool,
|
||||
webFetchTool,
|
||||
simulateRouteTool,
|
||||
|
||||
@@ -93,6 +93,8 @@ import { normalizeQuotaResponse } from "../../src/shared/contracts/quota.ts";
|
||||
import { resolveOmniRouteBaseUrl } from "../../src/shared/utils/resolveOmniRouteBaseUrl.ts";
|
||||
import { sanitizeErrorMessage } from "../utils/error.ts";
|
||||
import { getMcpModelsCatalog } from "./catalog.ts";
|
||||
import { registerRadarCatalogTool } from "./radarCatalog.ts";
|
||||
import type { TextToolResult } from "./toolResult.ts";
|
||||
export { getMcpModelsCatalog } from "./catalog.ts";
|
||||
|
||||
const OMNIROUTE_BASE_URL = resolveOmniRouteBaseUrl();
|
||||
@@ -146,11 +148,6 @@ function readMcpAccessibilityConfig(): McpAccessibilityConfig {
|
||||
}
|
||||
}
|
||||
|
||||
type TextToolResult = {
|
||||
content: Array<{ type: "text"; text: string }>;
|
||||
isError?: boolean;
|
||||
};
|
||||
|
||||
function toRecord(value: unknown): JsonRecord {
|
||||
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {};
|
||||
}
|
||||
@@ -842,6 +839,8 @@ export function createMcpServer(): McpServer {
|
||||
)
|
||||
);
|
||||
|
||||
registerRadarCatalogTool(server, withScopeEnforcement);
|
||||
|
||||
server.registerTool(
|
||||
"omniroute_simulate_route",
|
||||
{
|
||||
|
||||
4
open-sse/mcp-server/toolResult.ts
Normal file
4
open-sse/mcp-server/toolResult.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export type TextToolResult = {
|
||||
content: Array<{ type: "text"; text: string }>;
|
||||
isError?: boolean;
|
||||
};
|
||||
@@ -158,6 +158,7 @@ function readCodeFacts() {
|
||||
'import {pluginTools} from "./open-sse/mcp-server/tools/pluginTools.ts";',
|
||||
'import {notionTools} from "./open-sse/mcp-server/tools/notionTools.ts";',
|
||||
'import {obsidianTools} from "./open-sse/mcp-server/tools/obsidianTools.ts";',
|
||||
'import {localCorpusTools} from "./open-sse/mcp-server/tools/localCorpusTools.ts";',
|
||||
'import {compressionTools} from "./open-sse/mcp-server/tools/compressionTools.ts";',
|
||||
// Live provider total — the SAME collections gen-provider-reference.ts unions, so the
|
||||
// doc-vs-live check below cannot drift from the generator's definition of "provider".
|
||||
@@ -169,21 +170,16 @@ function readCodeFacts() {
|
||||
"const pids=new Set();",
|
||||
"for(const c of provCols)for(const p of Object.values(c||{}))if(p&&p.id)pids.add(p.id);",
|
||||
"const cols={MCP_TOOLS,memoryTools,skillTools,agentSkillTools,githubSkillTools,poolTools,",
|
||||
"gamificationTools,pluginTools,notionTools,obsidianTools,compressionTools};",
|
||||
"gamificationTools,pluginTools,notionTools,obsidianTools,localCorpusTools,compressionTools};",
|
||||
"const sc=new Set();",
|
||||
"for(const col of Object.values(cols))for(const t of Object.values(col))",
|
||||
"for(const x of (t?.scopes||[]))sc.add(x);",
|
||||
"const t=computeFreeModelTotals();const cli=Object.values(CLI_TOOLS);",
|
||||
"const by=(c)=>cli.filter(x=>x.category===c).length;",
|
||||
// "Free forever" = every provider whose free access renews or needs no key at all.
|
||||
// one-time-initial (signup credits) and discontinued pools are excluded on purpose.
|
||||
"const FOREVER=new Set(['recurring-monthly','recurring-daily','recurring-uncapped',",
|
||||
"'recurring-credit','keyless']);",
|
||||
"const ff=new Set();for(const m of t.perModel)if(FOREVER.has(m.freeType))ff.add(m.provider);",
|
||||
'console.log("@@"+JSON.stringify({freeSteady:t.steadyRecurringTokens,',
|
||||
"freeFirst:t.firstMonthRealisticTokens,freePools:t.poolCount,engines:ENGINE_IDS.length,",
|
||||
"cliTotal:cli.length,cliCode:by('code'),cliAgent:by('agent'),",
|
||||
"mcpTools:countUniqueMcpTools(cols),mcpScopes:sc.size,providers:pids.size,freeForever:ff.size}));",
|
||||
"mcpTools:countUniqueMcpTools(cols),mcpScopes:sc.size,providers:pids.size}));",
|
||||
].join("");
|
||||
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "docs-counts-"));
|
||||
try {
|
||||
@@ -457,7 +453,7 @@ export function buildChecks() {
|
||||
// total ("33 tools (25 CLI Code's …)") are not the MCP aggregate
|
||||
// per-module rows read "… tool definitions (N tools" / "… management tools
|
||||
// (N tools" — the word tool(s)/definitions sits right before the paren. The
|
||||
// aggregate ("MCP Server (104 tools", "all 104 tools") never does.
|
||||
// aggregate ("MCP Server (109 tools", "all 109 tools") never does.
|
||||
skipBefore: /(tools?|definitions?)\s*\(\s*$/i,
|
||||
skipAfter: /^\s*\(\d+ CLI/,
|
||||
},
|
||||
@@ -465,10 +461,6 @@ export function buildChecks() {
|
||||
),
|
||||
claim(f.mcpScopes, "MCP scopes", { pattern: /(\d+) scopes/gi }, ["README.md", "AGENTS.md"]),
|
||||
claim(f.cliTotal, "CLI tools", { pattern: /(\d+) tools(?=\s*\(\d+ CLI)/gi }, ["README.md"]),
|
||||
claim(f.freeForever, "free-forever providers", { pattern: /(\d+) free forever/gi }, [
|
||||
"README.md",
|
||||
"docs/diagrams/promise-pillars.svg",
|
||||
]),
|
||||
];
|
||||
})(),
|
||||
{
|
||||
|
||||
@@ -43,15 +43,14 @@ export const KNOWN_DUPLICATE_VERSIONS = new Set([
|
||||
// ---------------------------------------------------------------------------
|
||||
// ALLOWLIST 2 — gaps de sequência CONHECIDOS.
|
||||
// Fonte: auditoria do disco (src/lib/db/migrations/). Além dos slots legados,
|
||||
// 144–145 seguem reservados pelas migrations Radar que já existem na série
|
||||
// empilhada; a migration 143 já aterrissou. O job registry foi promovido de 139
|
||||
// para 146 pela tabela RENAMED_MIGRATION_COMPATIBILITY. A
|
||||
// As migrations Radar 144–145 e a migration 143 já aterrissaram. O job registry
|
||||
// foi promovido de 139 para 146 pela tabela RENAMED_MIGRATION_COMPATIBILITY. A
|
||||
// 147–149 estão reservadas por migrations atualmente em trânsito nos PRs #8228,
|
||||
// #9313, #10047 e #10066; esta branch usa 150 para evitar essas colisões conhecidas.
|
||||
// O stale-enforcement exige que cada reserva seja removida quando os arquivos
|
||||
// correspondentes aterrissarem na release.
|
||||
// ---------------------------------------------------------------------------
|
||||
export const KNOWN_GAPS = new Set(["026", "055", "121", "144", "145", "148", "149"]); // 121: número queimado no ciclo v3.8.47 — 122 (#6909) mergeou antes e 121 nunca aterrissou (validação e2e 2026-07-12)
|
||||
export const KNOWN_GAPS = new Set(["026", "055", "121", "148", "149"]); // 121: número queimado no ciclo v3.8.47 — 122 (#6909) mergeou antes e 121 nunca aterrissou (validação e2e 2026-07-12)
|
||||
|
||||
function pad3(n) {
|
||||
return String(n).padStart(3, "0");
|
||||
|
||||
@@ -22,7 +22,6 @@ import { HomeProviderTopologySection } from "./HomeProviderTopologySection";
|
||||
import { shouldShowProviderTopologyOnHome } from "./homeAppearance";
|
||||
|
||||
const ProviderQuotaWidget = dynamic(() => import("../home/ProviderQuotaWidget"), { ssr: false });
|
||||
import type { NewsAnnouncement } from "@/shared/utils/releaseNotes";
|
||||
|
||||
type UpdateStep = {
|
||||
step: string;
|
||||
@@ -37,7 +36,6 @@ type VersionInfo = {
|
||||
channel: string;
|
||||
autoUpdateSupported: boolean;
|
||||
autoUpdateError?: string | null;
|
||||
news?: NewsAnnouncement | null;
|
||||
};
|
||||
|
||||
type HomePageClientProps = {
|
||||
@@ -1047,37 +1045,6 @@ export default function HomePageClient({ machineId }: HomePageClientProps) {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* News Notification Banner */}
|
||||
{versionInfo?.news && (
|
||||
<div className="flex min-h-[64px] items-center justify-between rounded-lg border border-border bg-surface px-5 py-4">
|
||||
<div className="flex min-w-0 items-center gap-4">
|
||||
<div className="flex size-10 shrink-0 items-center justify-center rounded-lg bg-bg text-text-muted">
|
||||
<span className="material-symbols-outlined text-[22px] text-primary">
|
||||
{versionInfo.news.icon || "campaign"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-semibold text-text-main">{versionInfo.news.title}</p>
|
||||
<p className="mt-0.5 max-w-[560px] text-xs leading-relaxed text-text-muted">
|
||||
{versionInfo.news.message}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{versionInfo.news.link && (
|
||||
<a
|
||||
href={versionInfo.news.link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="ml-4 inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-border bg-bg px-4 py-2 text-xs font-semibold text-text-main transition-colors hover:border-primary/30 hover:text-primary"
|
||||
>
|
||||
{versionInfo.news.linkLabel || t("readMore")}
|
||||
<span className="material-symbols-outlined text-[14px]">arrow_forward</span>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
119
src/app/(dashboard)/dashboard/NewsBanner.tsx
Normal file
119
src/app/(dashboard)/dashboard/NewsBanner.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState, useSyncExternalStore } from "react";
|
||||
import { useLocale, useTranslations } from "next-intl";
|
||||
|
||||
import {
|
||||
NEWS_DISMISS_EVENT,
|
||||
NEWS_DISMISS_STORAGE_NAME,
|
||||
fetchNewsPayload,
|
||||
parseDismissedNewsIds,
|
||||
selectActiveNews,
|
||||
serializeDismissedNewsIds,
|
||||
} from "@/shared/utils/releaseNotes";
|
||||
|
||||
function subscribeToDismissals(callback: () => void) {
|
||||
window.addEventListener("storage", callback);
|
||||
window.addEventListener(NEWS_DISMISS_EVENT, callback);
|
||||
return () => {
|
||||
window.removeEventListener("storage", callback);
|
||||
window.removeEventListener(NEWS_DISMISS_EVENT, callback);
|
||||
};
|
||||
}
|
||||
|
||||
function readDismissedIds(): string {
|
||||
try {
|
||||
return localStorage.getItem(NEWS_DISMISS_STORAGE_NAME) ?? "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function getServerDismissedIds(): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic, fail-silent reader for the public announcement feed. Fetching the
|
||||
* static JSON is GET-only and does not send product state or telemetry.
|
||||
*/
|
||||
export default function NewsBanner() {
|
||||
const locale = useLocale();
|
||||
const t = useTranslations("common");
|
||||
const [payload, setPayload] = useState<unknown>(null);
|
||||
const dismissedSnapshot = useSyncExternalStore(
|
||||
subscribeToDismissals,
|
||||
readDismissedIds,
|
||||
getServerDismissedIds
|
||||
);
|
||||
const dismissedIds = parseDismissedNewsIds(dismissedSnapshot);
|
||||
const announcement = selectActiveNews(payload, locale, dismissedIds);
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
|
||||
void fetchNewsPayload(fetch, controller.signal).then((value) => {
|
||||
if (value !== null) setPayload(value);
|
||||
});
|
||||
|
||||
return () => controller.abort();
|
||||
}, []);
|
||||
|
||||
if (!announcement) return null;
|
||||
|
||||
const dismiss = () => {
|
||||
dismissedIds.add(announcement.id);
|
||||
try {
|
||||
localStorage.setItem(NEWS_DISMISS_STORAGE_NAME, serializeDismissedNewsIds(dismissedIds));
|
||||
} catch {
|
||||
// Storage is optional; the next announcement fetch remains functional.
|
||||
}
|
||||
window.dispatchEvent(new Event(NEWS_DISMISS_EVENT));
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
role="complementary"
|
||||
aria-label={announcement.title}
|
||||
className="mb-4 flex flex-col gap-3 rounded-lg border border-primary/30 bg-primary/5 px-4 py-3 sm:flex-row sm:items-center sm:justify-between"
|
||||
>
|
||||
<div className="flex min-w-0 items-start gap-3">
|
||||
<div className="flex size-9 shrink-0 items-center justify-center rounded-lg bg-primary/10">
|
||||
<span className="material-symbols-outlined text-[22px] text-primary" aria-hidden="true">
|
||||
{announcement.icon}
|
||||
</span>
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-semibold text-text-main">{announcement.title}</p>
|
||||
<p className="mt-0.5 text-xs leading-relaxed text-text-muted">{announcement.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex shrink-0 items-center gap-3 self-end sm:self-auto">
|
||||
{announcement.link && (
|
||||
<a
|
||||
href={announcement.link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1.5 whitespace-nowrap rounded-lg bg-primary px-3 py-1.5 text-xs font-semibold text-white transition-colors hover:brightness-110"
|
||||
>
|
||||
{announcement.linkLabel ?? announcement.title}
|
||||
<span className="material-symbols-outlined text-[14px]" aria-hidden="true">
|
||||
open_in_new
|
||||
</span>
|
||||
</a>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={dismiss}
|
||||
aria-label={t("dismissNotification")}
|
||||
className="text-text-muted transition-colors hover:text-text-main"
|
||||
>
|
||||
<span className="material-symbols-outlined text-[18px]" aria-hidden="true">
|
||||
close
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,39 +1,39 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useLocale, useTranslations } from "next-intl";
|
||||
|
||||
import { Button } from "@/shared/components";
|
||||
import {
|
||||
NEWS_JSON_URL,
|
||||
parseActiveNewsPayload,
|
||||
fetchNewsPayload,
|
||||
listActiveNews,
|
||||
type NewsAnnouncement,
|
||||
} from "@/shared/utils/releaseNotes";
|
||||
|
||||
export default function NewsViewer() {
|
||||
const locale = useLocale();
|
||||
const t = useTranslations("changelogPage");
|
||||
const [news, setNews] = useState<NewsAnnouncement | null>(null);
|
||||
const [news, setNews] = useState<NewsAnnouncement[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchNews() {
|
||||
try {
|
||||
const res = await fetch(NEWS_JSON_URL, { cache: "no-store" });
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
setNews(parseActiveNewsPayload(data));
|
||||
} else {
|
||||
setError(true);
|
||||
const controller = new AbortController();
|
||||
|
||||
void fetchNewsPayload(fetch, controller.signal)
|
||||
.then((payload) => {
|
||||
if (payload === null) {
|
||||
if (!controller.signal.aborted) setError(true);
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch news:", err);
|
||||
setError(true);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
fetchNews();
|
||||
}, []);
|
||||
setNews(listActiveNews(payload, locale));
|
||||
})
|
||||
.finally(() => {
|
||||
if (!controller.signal.aborted) setLoading(false);
|
||||
});
|
||||
|
||||
return () => controller.abort();
|
||||
}, [locale]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
@@ -48,7 +48,7 @@ export default function NewsViewer() {
|
||||
if (error) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center py-20 text-text-muted">
|
||||
<span className="material-symbols-outlined text-[48px] text-red-500/50 mb-4">
|
||||
<span className="material-symbols-outlined mb-4 text-[48px] text-red-500/50">
|
||||
error_outline
|
||||
</span>
|
||||
<p>{t("announcementsLoadFailed")}</p>
|
||||
@@ -56,10 +56,10 @@ export default function NewsViewer() {
|
||||
);
|
||||
}
|
||||
|
||||
if (!news || !news.active) {
|
||||
if (news.length === 0) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center py-20 text-text-muted">
|
||||
<span className="material-symbols-outlined text-[48px] opacity-50 mb-4">
|
||||
<span className="material-symbols-outlined mb-4 text-[48px] opacity-50">
|
||||
notifications_off
|
||||
</span>
|
||||
<p>{t("noAnnouncements")}</p>
|
||||
@@ -68,30 +68,37 @@ export default function NewsViewer() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="flex flex-col gap-6 border-l-4 border-primary pl-5 md:flex-row md:items-center md:pl-6">
|
||||
<div className="size-14 rounded-lg bg-primary/10 flex items-center justify-center shrink-0">
|
||||
<span className="material-symbols-outlined text-[30px] text-primary">
|
||||
{news.icon || "campaign"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<h2 className="text-xl font-bold text-text-main mb-2">{news.title}</h2>
|
||||
<p className="text-sm text-text-muted leading-relaxed max-w-2xl">{news.message}</p>
|
||||
</div>
|
||||
|
||||
{news.link && (
|
||||
<div className="shrink-0 md:ml-auto">
|
||||
<a href={news.link} target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="primary" className="gap-2">
|
||||
{news.linkLabel || t("learnMore")}
|
||||
<span className="material-symbols-outlined text-[18px]">arrow_forward</span>
|
||||
</Button>
|
||||
</a>
|
||||
<div className="space-y-8 p-8">
|
||||
{news.map((announcement) => (
|
||||
<article
|
||||
key={announcement.id}
|
||||
className="flex flex-col gap-6 border-l-4 border-primary pl-5 md:flex-row md:items-center md:pl-6"
|
||||
>
|
||||
<div className="flex size-14 shrink-0 items-center justify-center rounded-lg bg-primary/10">
|
||||
<span className="material-symbols-outlined text-[30px] text-primary">
|
||||
{announcement.icon}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<h2 className="mb-2 text-xl font-bold text-text-main">{announcement.title}</h2>
|
||||
<p className="max-w-2xl text-sm leading-relaxed text-text-muted">
|
||||
{announcement.message}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{announcement.link && (
|
||||
<div className="shrink-0 md:ml-auto">
|
||||
<a href={announcement.link} target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="primary" className="gap-2">
|
||||
{announcement.linkLabel ?? t("learnMore")}
|
||||
<span className="material-symbols-outlined text-[18px]">arrow_forward</span>
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// Issue #3501 strangler-fig decomposition — Phase 1t (final push)
|
||||
import { useState, useEffect, useCallback, useMemo } from "react";
|
||||
import { useParams } from "next/navigation";
|
||||
import { useParams, useSearchParams } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Card, Button, CardSkeleton } from "@/shared/components";
|
||||
@@ -68,6 +68,7 @@ import AnonymousFallbackToggle from "./components/AnonymousFallbackToggle";
|
||||
|
||||
export default function ProviderDetailPageClient() {
|
||||
const params = useParams();
|
||||
const searchParams = useSearchParams();
|
||||
const providerId = params.id as string;
|
||||
|
||||
// ── UI-only modal state (not owned by hooks) ─────────────────────────────
|
||||
@@ -357,6 +358,10 @@ export default function ProviderDetailPageClient() {
|
||||
setShowAddApiKeyModal(true);
|
||||
}, [providerId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (searchParams.get("action") === "add-api-key") gateConnectionFlow(openApiKeyAddFlow);
|
||||
}, [searchParams, gateConnectionFlow, openApiKeyAddFlow]);
|
||||
|
||||
const openPrimaryAddFlow = useCallback(() => {
|
||||
if (providerId === "kimi-coding") return setShowKimiAuthMethodModal(true);
|
||||
if (isOAuth) {
|
||||
|
||||
381
src/app/(dashboard)/dashboard/radar/RadarCatalogTable.tsx
Normal file
381
src/app/(dashboard)/dashboard/radar/RadarCatalogTable.tsx
Normal file
@@ -0,0 +1,381 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Card } from "@/shared/components";
|
||||
|
||||
export interface RadarMergedEntry {
|
||||
provider: string;
|
||||
modelId: string;
|
||||
displayName: string;
|
||||
monthlyTokens: number;
|
||||
creditTokens: number;
|
||||
freeType: string;
|
||||
poolKey: string | null;
|
||||
tos: string;
|
||||
trainsOnPrompts?: boolean;
|
||||
enabled?: boolean;
|
||||
origin: "baseline" | "radar" | "local";
|
||||
disabledBy?: "radar";
|
||||
contextWindow?: number | null;
|
||||
capabilities?: {
|
||||
tools: boolean | null;
|
||||
vision: boolean | null;
|
||||
thinking: boolean | null;
|
||||
};
|
||||
metadataEvidenceUrls?: string[];
|
||||
budget?: { kind: string; tokensPerMonth?: number; poolId?: string };
|
||||
limits?: { rpm: number | null; rpd: number | null; tpm: number | null; tpd: number | null };
|
||||
setup?: { keyUrl: string | null; steps: string[] } | null;
|
||||
}
|
||||
|
||||
interface RadarLocalModelState {
|
||||
provider: string;
|
||||
modelId: string;
|
||||
displayName: string | null;
|
||||
enabled: boolean | null;
|
||||
tombstoned: boolean;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
interface RadarCatalogTableProps {
|
||||
entries: RadarMergedEntry[];
|
||||
refreshCatalog: () => Promise<void>;
|
||||
onError: (message: string) => void;
|
||||
}
|
||||
|
||||
function formatTokens(value: number): string {
|
||||
if (value === 0) return "rate-only";
|
||||
if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`;
|
||||
if (value >= 1_000) return `${(value / 1_000).toFixed(0)}K`;
|
||||
return String(value);
|
||||
}
|
||||
|
||||
function budgetLabel(entry: RadarMergedEntry): string {
|
||||
if (entry.budget?.kind === "shared_pool") {
|
||||
return `shared (${formatTokens(entry.budget.tokensPerMonth ?? entry.monthlyTokens)}/mo)`;
|
||||
}
|
||||
if (entry.budget?.kind === "rate_only" || entry.monthlyTokens === 0) return "rate-only";
|
||||
return `${formatTokens(entry.monthlyTokens)}/mo`;
|
||||
}
|
||||
|
||||
function capabilityBadge(label: string, value: boolean | null | undefined, trueClass: string) {
|
||||
const state = value === true ? "✓" : value === false ? "✕" : "?";
|
||||
const stateClass =
|
||||
value === true
|
||||
? trueClass
|
||||
: value === false
|
||||
? "bg-red-500/10 text-red-400"
|
||||
: "bg-gray-500/10 text-gray-400";
|
||||
return (
|
||||
<span className={`text-[10px] px-1.5 py-0.5 rounded ${stateClass}`}>
|
||||
{label} {state}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export function RadarCatalogTable({ entries, refreshCatalog, onError }: RadarCatalogTableProps) {
|
||||
const t = useTranslations("radarPage");
|
||||
const [states, setStates] = useState<RadarLocalModelState[]>([]);
|
||||
const [editingKey, setEditingKey] = useState<string | null>(null);
|
||||
const [displayName, setDisplayName] = useState("");
|
||||
const [enabled, setEnabled] = useState(true);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
const loadState = useCallback(async () => {
|
||||
try {
|
||||
const response = await fetch("/api/radar/local-model-state");
|
||||
if (!response.ok) return;
|
||||
const payload = await response.json();
|
||||
setStates(Array.isArray(payload.states) ? payload.states : []);
|
||||
} catch {
|
||||
onError(t("errorLoading"));
|
||||
}
|
||||
}, [onError, t]);
|
||||
|
||||
useEffect(() => {
|
||||
void loadState();
|
||||
}, [loadState]);
|
||||
|
||||
const stateByKey = useMemo(
|
||||
() => new Map(states.map((state) => [`${state.provider}:${state.modelId}`, state])),
|
||||
[states]
|
||||
);
|
||||
const hiddenModels = useMemo(() => states.filter((state) => state.tombstoned), [states]);
|
||||
|
||||
const applyResponse = useCallback(async (response: Response) => {
|
||||
if (!response.ok) throw new Error("save_failed");
|
||||
const payload = await response.json();
|
||||
setStates(Array.isArray(payload.states) ? payload.states : []);
|
||||
}, []);
|
||||
|
||||
const mutate = useCallback(
|
||||
async (operation: () => Promise<Response>) => {
|
||||
setSaving(true);
|
||||
onError("");
|
||||
try {
|
||||
await applyResponse(await operation());
|
||||
setEditingKey(null);
|
||||
await refreshCatalog();
|
||||
} catch {
|
||||
onError(t("localStateSaveFailed"));
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
},
|
||||
[applyResponse, onError, refreshCatalog, t]
|
||||
);
|
||||
|
||||
const beginEdit = useCallback((entry: RadarMergedEntry) => {
|
||||
setEditingKey(`${entry.provider}:${entry.modelId}`);
|
||||
setDisplayName(entry.displayName);
|
||||
setEnabled(entry.enabled !== false);
|
||||
}, []);
|
||||
|
||||
const saveOverride = useCallback(
|
||||
(entry: RadarMergedEntry) =>
|
||||
mutate(() =>
|
||||
fetch("/api/radar/local-model-state", {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
provider: entry.provider,
|
||||
modelId: entry.modelId,
|
||||
displayName,
|
||||
enabled,
|
||||
}),
|
||||
})
|
||||
),
|
||||
[displayName, enabled, mutate]
|
||||
);
|
||||
|
||||
const resetOverride = useCallback(
|
||||
(entry: Pick<RadarMergedEntry, "provider" | "modelId">) => {
|
||||
const query = new URLSearchParams({ provider: entry.provider, modelId: entry.modelId });
|
||||
return mutate(() =>
|
||||
fetch(`/api/radar/local-model-state?${query.toString()}`, { method: "DELETE" })
|
||||
);
|
||||
},
|
||||
[mutate]
|
||||
);
|
||||
|
||||
const setTombstone = useCallback(
|
||||
(provider: string, modelId: string, tombstoned: boolean) =>
|
||||
mutate(() =>
|
||||
fetch("/api/radar/local-model-state", {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ provider, modelId, tombstoned }),
|
||||
})
|
||||
),
|
||||
[mutate]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full">
|
||||
<thead>
|
||||
<tr className="text-left text-sm text-text-muted border-b border-border">
|
||||
<th className="pb-3 font-medium">{t("colProvider")}</th>
|
||||
<th className="pb-3 font-medium">{t("colModel")}</th>
|
||||
<th className="pb-3 font-medium">{t("colQuota")}</th>
|
||||
<th className="pb-3 font-medium">{t("colContext")}</th>
|
||||
<th className="pb-3 font-medium">{t("colCapabilities")}</th>
|
||||
<th className="pb-3 font-medium">{t("colTos")}</th>
|
||||
<th className="pb-3 font-medium text-right">{t("colActions")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{entries.map((entry) => {
|
||||
const key = `${entry.provider}:${entry.modelId}`;
|
||||
const localState = stateByKey.get(key);
|
||||
const hasOverride =
|
||||
localState && (localState.displayName !== null || localState.enabled !== null);
|
||||
return (
|
||||
<tr
|
||||
key={key}
|
||||
className={`border-b border-border/50 last:border-b-0 ${
|
||||
entry.enabled === false ? "opacity-50" : ""
|
||||
}`}
|
||||
>
|
||||
<td className="py-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium">{entry.provider}</span>
|
||||
{entry.origin === "radar" && (
|
||||
<span className="text-[10px] px-1.5 py-0.5 rounded bg-violet-500/10 text-violet-400 font-medium">
|
||||
{t("newBadge")}
|
||||
</span>
|
||||
)}
|
||||
{entry.origin === "local" && (
|
||||
<span className="text-[10px] px-1.5 py-0.5 rounded bg-blue-500/10 text-blue-400 font-medium">
|
||||
{t("localBadge")}
|
||||
</span>
|
||||
)}
|
||||
{entry.setup?.keyUrl && (
|
||||
<Link
|
||||
href={`/dashboard/radar/setup?provider=${encodeURIComponent(entry.provider)}`}
|
||||
className="text-xs text-violet-400 hover:underline"
|
||||
title={t("setupGuide")}
|
||||
>
|
||||
⚙
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
{entry.enabled === false && entry.disabledBy === "radar" && (
|
||||
<p className="text-xs text-red-400 mt-0.5">{t("disabledByFeed")}</p>
|
||||
)}
|
||||
</td>
|
||||
<td className="py-3 text-text-muted text-sm font-mono max-w-[240px]">
|
||||
{editingKey === key ? (
|
||||
<input
|
||||
type="text"
|
||||
value={displayName}
|
||||
onChange={(event) => setDisplayName(event.target.value)}
|
||||
aria-label={t("modelDisplayName")}
|
||||
maxLength={160}
|
||||
className="w-full min-w-[180px] px-2 py-1 rounded border border-border bg-transparent text-text-main focus:outline-none focus:ring-2 focus:ring-violet-500"
|
||||
/>
|
||||
) : (
|
||||
<span className="block truncate">{entry.displayName}</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="py-3 text-sm">{budgetLabel(entry)}</td>
|
||||
<td className="py-3 text-sm text-text-muted">
|
||||
{entry.contextWindow ? `${(entry.contextWindow / 1000).toFixed(0)}K` : "—"}
|
||||
</td>
|
||||
<td className="py-3">
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{capabilityBadge(
|
||||
t("capTools"),
|
||||
entry.capabilities?.tools,
|
||||
"bg-blue-500/10 text-blue-400"
|
||||
)}
|
||||
{capabilityBadge(
|
||||
t("capVision"),
|
||||
entry.capabilities?.vision,
|
||||
"bg-purple-500/10 text-purple-400"
|
||||
)}
|
||||
{capabilityBadge(
|
||||
t("capThinking"),
|
||||
entry.capabilities?.thinking,
|
||||
"bg-amber-500/10 text-amber-400"
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="py-3">
|
||||
<span
|
||||
className={`text-xs px-2 py-1 rounded ${
|
||||
entry.tos === "ok"
|
||||
? "bg-green-500/10 text-green-400"
|
||||
: entry.tos === "caution"
|
||||
? "bg-yellow-500/10 text-yellow-400"
|
||||
: entry.tos === "avoid"
|
||||
? "bg-red-500/10 text-red-400"
|
||||
: "bg-gray-500/10 text-gray-400"
|
||||
}`}
|
||||
>
|
||||
{entry.tos}
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3 pl-3">
|
||||
{editingKey === key ? (
|
||||
<div className="flex flex-wrap items-center justify-end gap-2">
|
||||
<label className="inline-flex items-center gap-1 text-xs text-text-muted">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={enabled}
|
||||
disabled={entry.disabledBy === "radar"}
|
||||
onChange={(event) => setEnabled(event.target.checked)}
|
||||
/>
|
||||
{t("modelEnabled")}
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
disabled={saving || displayName.trim().length === 0}
|
||||
onClick={() => void saveOverride(entry)}
|
||||
className="text-xs text-violet-400 hover:underline disabled:opacity-50"
|
||||
>
|
||||
{t("saveModel")}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
disabled={saving}
|
||||
onClick={() => setEditingKey(null)}
|
||||
className="text-xs text-text-muted hover:text-text-main disabled:opacity-50"
|
||||
>
|
||||
{t("cancelEdit")}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-wrap items-center justify-end gap-2">
|
||||
<button
|
||||
type="button"
|
||||
disabled={saving}
|
||||
onClick={() => beginEdit(entry)}
|
||||
className="text-xs text-violet-400 hover:underline disabled:opacity-50"
|
||||
>
|
||||
{t("editModel")}
|
||||
</button>
|
||||
{hasOverride && (
|
||||
<button
|
||||
type="button"
|
||||
disabled={saving}
|
||||
onClick={() => void resetOverride(entry)}
|
||||
className="text-xs text-text-muted hover:text-text-main disabled:opacity-50"
|
||||
>
|
||||
{t("resetModel")}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
disabled={saving}
|
||||
onClick={() => void setTombstone(entry.provider, entry.modelId, true)}
|
||||
className="text-xs text-red-400 hover:underline disabled:opacity-50"
|
||||
>
|
||||
{t("hideModel")}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{hiddenModels.length > 0 && (
|
||||
<Card>
|
||||
<div className="flex flex-col gap-3">
|
||||
<h3 className="text-sm font-semibold">{t("hiddenModelsTitle")}</h3>
|
||||
{hiddenModels.map((state) => (
|
||||
<div
|
||||
key={`${state.provider}:${state.modelId}:hidden`}
|
||||
className="flex flex-wrap items-center justify-between gap-3 border-b border-border/50 pb-3 last:border-b-0 last:pb-0"
|
||||
>
|
||||
<div>
|
||||
<span className="font-medium">{state.provider}</span>
|
||||
<span className="ml-2 text-sm font-mono text-text-muted">
|
||||
{state.displayName ?? state.modelId}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
disabled={saving}
|
||||
onClick={() => void setTombstone(state.provider, state.modelId, false)}
|
||||
className="text-sm text-violet-400 hover:underline disabled:opacity-50"
|
||||
>
|
||||
{t("restoreModel")}
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
201
src/app/(dashboard)/dashboard/radar/combos/page.tsx
Normal file
201
src/app/(dashboard)/dashboard/radar/combos/page.tsx
Normal file
@@ -0,0 +1,201 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
import type { ComboBuilderOptionsPayload } from "@/lib/combos/builderOptions";
|
||||
import type { MergedEntry } from "@/lib/radar/applyFeed";
|
||||
import {
|
||||
buildRadarComboSuggestions,
|
||||
type RadarComboSuggestion,
|
||||
} from "@/lib/radar/comboSuggestions";
|
||||
import { Card } from "@/shared/components";
|
||||
|
||||
interface RadarCatalogPayload {
|
||||
entries?: MergedEntry[];
|
||||
meta?: unknown;
|
||||
}
|
||||
|
||||
function comboNames(payload: ComboBuilderOptionsPayload): Set<string> {
|
||||
return new Set(payload.comboRefs.map((combo) => combo.name));
|
||||
}
|
||||
|
||||
export default function RadarCombosPage() {
|
||||
const t = useTranslations("radarCombosPage");
|
||||
const [entries, setEntries] = useState<MergedEntry[]>([]);
|
||||
const [providers, setProviders] = useState<ComboBuilderOptionsPayload["providers"]>([]);
|
||||
const [existingNames, setExistingNames] = useState<Set<string>>(new Set());
|
||||
const [createdNames, setCreatedNames] = useState<Set<string>>(new Set());
|
||||
const [hasCatalog, setHasCatalog] = useState(false);
|
||||
const [flagOff, setFlagOff] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [creatingName, setCreatingName] = useState<string | null>(null);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
async function load() {
|
||||
try {
|
||||
const [catalogResponse, optionsResponse] = await Promise.all([
|
||||
fetch("/api/radar/catalog"),
|
||||
fetch("/api/combos/builder/options"),
|
||||
]);
|
||||
if (catalogResponse.status === 404) {
|
||||
setFlagOff(true);
|
||||
return;
|
||||
}
|
||||
if (!catalogResponse.ok || !optionsResponse.ok) throw new Error("load_failed");
|
||||
|
||||
const catalog = (await catalogResponse.json()) as RadarCatalogPayload;
|
||||
const options = (await optionsResponse.json()) as ComboBuilderOptionsPayload;
|
||||
if (!Array.isArray(catalog.entries) || !Array.isArray(options.providers)) {
|
||||
throw new Error("invalid_shape");
|
||||
}
|
||||
|
||||
setEntries(catalog.entries);
|
||||
setProviders(options.providers);
|
||||
setExistingNames(comboNames(options));
|
||||
setHasCatalog(catalog.meta != null);
|
||||
} catch {
|
||||
setError(t("loadFailed"));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
void load();
|
||||
}, [t]);
|
||||
|
||||
const suggestions = useMemo(
|
||||
() => buildRadarComboSuggestions({ entries, providers, existingComboNames: existingNames }),
|
||||
[entries, providers, existingNames]
|
||||
);
|
||||
|
||||
const refreshExistingName = useCallback(async (name: string): Promise<boolean> => {
|
||||
try {
|
||||
const response = await fetch("/api/combos/builder/options");
|
||||
if (!response.ok) return false;
|
||||
const options = (await response.json()) as ComboBuilderOptionsPayload;
|
||||
if (!Array.isArray(options.comboRefs)) return false;
|
||||
const names = comboNames(options);
|
||||
if (![...names].some((candidate) => candidate.toLowerCase() === name.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
setExistingNames(names);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const createSuggestion = useCallback(
|
||||
async (suggestion: RadarComboSuggestion) => {
|
||||
setCreatingName(suggestion.name);
|
||||
setError("");
|
||||
try {
|
||||
const response = await fetch("/api/combos", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(suggestion.payload),
|
||||
});
|
||||
if (!response.ok) {
|
||||
if (response.status === 400 && (await refreshExistingName(suggestion.name))) return;
|
||||
throw new Error("create_failed");
|
||||
}
|
||||
setExistingNames((current) => new Set([...current, suggestion.name]));
|
||||
setCreatedNames((current) => new Set([...current, suggestion.name]));
|
||||
} catch {
|
||||
setError(t("createFailed"));
|
||||
} finally {
|
||||
setCreatingName(null);
|
||||
}
|
||||
},
|
||||
[refreshExistingName, t]
|
||||
);
|
||||
|
||||
if (flagOff) notFound();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-col gap-3">
|
||||
<Link
|
||||
href="/dashboard/radar"
|
||||
className="text-sm text-text-muted hover:text-text-main transition-colors w-fit"
|
||||
>
|
||||
← {t("backToRadar")}
|
||||
</Link>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold">{t("title")}</h1>
|
||||
<p className="text-sm text-text-muted mt-1">{t("subtitle")}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{error && <div className="p-3 rounded-lg bg-red-500/10 text-red-400 text-sm">{error}</div>}
|
||||
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center min-h-[200px] text-text-muted">
|
||||
{t("loading")}
|
||||
</div>
|
||||
) : !hasCatalog ? (
|
||||
<Card>
|
||||
<p className="text-center text-text-muted py-8">{t("catalogRequired")}</p>
|
||||
</Card>
|
||||
) : suggestions.length === 0 ? (
|
||||
<Card>
|
||||
<p className="text-center text-text-muted py-8">{t("noSuggestions")}</p>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="grid gap-4">
|
||||
{suggestions.map((suggestion) => {
|
||||
const creating = creatingName === suggestion.name;
|
||||
const created = createdNames.has(suggestion.name);
|
||||
return (
|
||||
<Card key={suggestion.familyId}>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-xs uppercase tracking-wide text-text-muted">
|
||||
{t("familyLabel")}
|
||||
</span>
|
||||
<h2 className="text-lg font-semibold font-mono">{suggestion.familyId}</h2>
|
||||
<p className="text-sm text-text-muted">{t("strategyReason")}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-sm font-medium">{t("modelsLabel")}</span>
|
||||
{suggestion.models.map((model) => (
|
||||
<div
|
||||
key={`${model.providerId}:${model.modelId}`}
|
||||
className="flex flex-wrap items-center justify-between gap-2 rounded-lg border border-border px-3 py-2"
|
||||
>
|
||||
<span className="font-medium">{model.providerName}</span>
|
||||
<span className="font-mono text-sm text-text-muted">
|
||||
{model.qualifiedModel}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => void createSuggestion(suggestion)}
|
||||
disabled={creating || suggestion.alreadyExists}
|
||||
className="self-start px-4 py-2 text-sm font-medium rounded-lg bg-violet-500 text-white hover:bg-violet-600 transition-colors disabled:opacity-50"
|
||||
>
|
||||
{created
|
||||
? t("created")
|
||||
: suggestion.alreadyExists
|
||||
? t("alreadyCreated")
|
||||
: creating
|
||||
? t("generating")
|
||||
: t("generateButton")}
|
||||
</button>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
197
src/app/(dashboard)/dashboard/radar/intel/page.tsx
Normal file
197
src/app/(dashboard)/dashboard/radar/intel/page.tsx
Normal file
@@ -0,0 +1,197 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
import type { RadarIntelFeed } from "@/lib/radar/intelFeedSchema";
|
||||
import { Card } from "@/shared/components";
|
||||
|
||||
interface IntelMeta {
|
||||
version: string;
|
||||
tier: "live";
|
||||
fetchedAt: string;
|
||||
supporterVerified: true;
|
||||
}
|
||||
|
||||
export default function RadarIntelPage() {
|
||||
const t = useTranslations("radarIntelPage");
|
||||
const [intel, setIntel] = useState<RadarIntelFeed | null>(null);
|
||||
const [meta, setMeta] = useState<IntelMeta | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [syncing, setSyncing] = useState(false);
|
||||
const [flagOff, setFlagOff] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const load = useCallback(async () => {
|
||||
const response = await fetch("/api/radar/intel");
|
||||
if (response.status === 404) {
|
||||
setFlagOff(true);
|
||||
return;
|
||||
}
|
||||
if (!response.ok) throw new Error("intel_load_failed");
|
||||
const body = (await response.json()) as {
|
||||
intel?: RadarIntelFeed | null;
|
||||
meta?: IntelMeta | null;
|
||||
};
|
||||
setIntel(body.intel ?? null);
|
||||
setMeta(body.meta ?? null);
|
||||
}, []);
|
||||
|
||||
const sync = useCallback(async () => {
|
||||
setSyncing(true);
|
||||
setError("");
|
||||
try {
|
||||
const response = await fetch("/api/radar/intel/sync", { method: "POST" });
|
||||
if (response.status === 404) {
|
||||
setFlagOff(true);
|
||||
return;
|
||||
}
|
||||
if (!response.ok) throw new Error("intel_sync_failed");
|
||||
const status = (await response.json()) as { status?: string };
|
||||
if (
|
||||
["error", "invalid_signature", "invalid_schema", "wrong_tier", "too_large"].includes(
|
||||
status.status ?? ""
|
||||
)
|
||||
) {
|
||||
setError(t("loadFailed"));
|
||||
}
|
||||
await load();
|
||||
} catch {
|
||||
setError(t("loadFailed"));
|
||||
await load().catch(() => undefined);
|
||||
} finally {
|
||||
setSyncing(false);
|
||||
}
|
||||
}, [load, t]);
|
||||
|
||||
useEffect(() => {
|
||||
load()
|
||||
.catch(() => setError(t("loadFailed")))
|
||||
.finally(() => setLoading(false));
|
||||
}, [load, t]);
|
||||
|
||||
if (flagOff) notFound();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||
<div>
|
||||
<Link
|
||||
href="/dashboard/radar"
|
||||
className="text-sm text-text-muted hover:text-text-main transition-colors"
|
||||
>
|
||||
← {t("backToRadar")}
|
||||
</Link>
|
||||
<h1 className="mt-3 text-2xl font-bold">{t("title")}</h1>
|
||||
<p className="mt-1 text-sm text-text-muted">{t("subtitle")}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{meta?.supporterVerified === true && (
|
||||
<span
|
||||
data-badge-id="radar-supporter"
|
||||
className="rounded-full border border-violet-500 px-3 py-1 text-sm text-violet-300"
|
||||
>
|
||||
{t("supporterBadge")}
|
||||
</span>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => void sync()}
|
||||
disabled={syncing}
|
||||
className="rounded-lg border border-violet-500 px-4 py-2 text-sm font-medium text-violet-400 disabled:opacity-50"
|
||||
>
|
||||
{syncing ? t("syncing") : t("refresh")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{error && <div className="rounded-lg bg-red-500/10 p-3 text-sm text-red-400">{error}</div>}
|
||||
|
||||
{loading ? (
|
||||
<div className="flex min-h-48 items-center justify-center text-text-muted">
|
||||
{t("loading")}
|
||||
</div>
|
||||
) : !intel || !meta ? (
|
||||
<Card>
|
||||
<p className="py-8 text-center text-text-muted">{t("empty")}</p>
|
||||
</Card>
|
||||
) : (
|
||||
<>
|
||||
<div className="grid gap-4 md:grid-cols-3">
|
||||
<Card>
|
||||
<p className="text-xs uppercase tracking-wide text-text-muted">{t("methodology")}</p>
|
||||
<p className="mt-2 font-semibold">
|
||||
{t("eloMethod", {
|
||||
initial: intel.methodology.initialRating,
|
||||
factor: intel.methodology.kFactor,
|
||||
})}
|
||||
</p>
|
||||
</Card>
|
||||
<Card>
|
||||
<p className="text-xs uppercase tracking-wide text-text-muted">{t("freshness")}</p>
|
||||
<p className="mt-2 font-semibold">
|
||||
{t(`freshnessValues.${intel.catalog.freshness}`)}
|
||||
</p>
|
||||
<p className="mt-1 text-sm text-text-muted">
|
||||
{t("ageDays", { days: intel.catalog.ageDays })}
|
||||
</p>
|
||||
</Card>
|
||||
<Card>
|
||||
<p className="text-xs uppercase tracking-wide text-text-muted">{t("trend")}</p>
|
||||
<p className="mt-2 font-semibold">{t(`trendValues.${intel.catalog.trend}`)}</p>
|
||||
<p className="mt-1 text-sm text-text-muted">
|
||||
{t("modelDelta", {
|
||||
current: intel.catalog.models.current,
|
||||
added: intel.catalog.models.added,
|
||||
removed: intel.catalog.models.removed,
|
||||
})}
|
||||
</p>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<div className="mb-4 flex items-center justify-between gap-3">
|
||||
<h2 className="text-lg font-semibold">{t("ranking")}</h2>
|
||||
<span className="text-xs text-text-muted">{meta.version}</span>
|
||||
</div>
|
||||
{intel.rankings.length === 0 ? (
|
||||
<p className="py-6 text-center text-text-muted">{t("noRankings")}</p>
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-left text-sm">
|
||||
<thead className="text-text-muted">
|
||||
<tr>
|
||||
<th className="pb-3">#</th>
|
||||
<th className="pb-3">{t("model")}</th>
|
||||
<th className="pb-3">{t("category")}</th>
|
||||
<th className="pb-3 text-right">{t("rating")}</th>
|
||||
<th className="pb-3 text-right">{t("matches")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{intel.rankings.map((ranking) => (
|
||||
<tr
|
||||
key={`${ranking.category}:${ranking.provider}:${ranking.modelId}`}
|
||||
className="border-t border-border"
|
||||
>
|
||||
<td className="py-3">{ranking.rank}</td>
|
||||
<td className="py-3 font-mono">
|
||||
{ranking.provider}/{ranking.modelId}
|
||||
</td>
|
||||
<td className="py-3">{ranking.category}</td>
|
||||
<td className="py-3 text-right">{ranking.rating}</td>
|
||||
<td className="py-3 text-right">{ranking.matches}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
273
src/app/(dashboard)/dashboard/radar/offers/page.tsx
Normal file
273
src/app/(dashboard)/dashboard/radar/offers/page.tsx
Normal file
@@ -0,0 +1,273 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import { useLocale, useTranslations } from "next-intl";
|
||||
|
||||
import {
|
||||
filterActiveRadarOffers,
|
||||
localizeRadarOfferText,
|
||||
type RadarOffer,
|
||||
type RadarOfferBenefit,
|
||||
} from "@/lib/radar/offersFeedSchema";
|
||||
import { Card } from "@/shared/components";
|
||||
|
||||
interface OffersMeta {
|
||||
version: string;
|
||||
tier: "live";
|
||||
fetchedAt: string;
|
||||
}
|
||||
|
||||
interface SettingsPayload {
|
||||
hasSupporterKey?: boolean;
|
||||
contributorClaimUrl?: string;
|
||||
supporterPlansUrl?: string;
|
||||
}
|
||||
|
||||
export default function RadarOffersPage() {
|
||||
const t = useTranslations("radarOffersPage");
|
||||
const locale = useLocale();
|
||||
const [offers, setOffers] = useState<RadarOffer[]>([]);
|
||||
const [meta, setMeta] = useState<OffersMeta | null>(null);
|
||||
const [hasSupporterKey, setHasSupporterKey] = useState(false);
|
||||
const [contributorClaimUrl, setContributorClaimUrl] = useState<string | null>(null);
|
||||
const [supporterPlansUrl, setSupporterPlansUrl] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [flagOff, setFlagOff] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const loadOffers = useCallback(async () => {
|
||||
const response = await fetch("/api/radar/offers");
|
||||
if (response.status === 404) {
|
||||
setFlagOff(true);
|
||||
return;
|
||||
}
|
||||
if (!response.ok) throw new Error("offers_load_failed");
|
||||
const body = (await response.json()) as { offers?: RadarOffer[]; meta?: OffersMeta | null };
|
||||
setOffers(Array.isArray(body.offers) ? body.offers : []);
|
||||
setMeta(body.meta ?? null);
|
||||
}, []);
|
||||
|
||||
const syncAndLoad = useCallback(async () => {
|
||||
setRefreshing(true);
|
||||
setError("");
|
||||
try {
|
||||
const response = await fetch("/api/radar/offers/sync", { method: "POST" });
|
||||
if (response.status === 404) {
|
||||
setFlagOff(true);
|
||||
return;
|
||||
}
|
||||
if (!response.ok) throw new Error("offers_sync_failed");
|
||||
const status = (await response.json()) as { status?: string; reason?: string };
|
||||
if (status.status === "no_key") {
|
||||
setHasSupporterKey(false);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
status.status === "error" ||
|
||||
status.status === "invalid_signature" ||
|
||||
status.status === "invalid_schema" ||
|
||||
status.status === "wrong_tier" ||
|
||||
status.status === "too_large"
|
||||
) {
|
||||
setError(t("loadFailed"));
|
||||
}
|
||||
// Preserve availability: even when refresh fails, render the last
|
||||
// verified local cache rather than clearing it.
|
||||
await loadOffers();
|
||||
} catch {
|
||||
setError(t("loadFailed"));
|
||||
try {
|
||||
await loadOffers();
|
||||
} catch {
|
||||
// The primary error already explains the failed local read.
|
||||
}
|
||||
} finally {
|
||||
setRefreshing(false);
|
||||
}
|
||||
}, [loadOffers, t]);
|
||||
|
||||
useEffect(() => {
|
||||
async function load(): Promise<void> {
|
||||
try {
|
||||
const response = await fetch("/api/radar/settings");
|
||||
if (response.status === 404) {
|
||||
setFlagOff(true);
|
||||
return;
|
||||
}
|
||||
if (!response.ok) throw new Error("settings_load_failed");
|
||||
const settings = (await response.json()) as SettingsPayload;
|
||||
const hasKey = settings.hasSupporterKey === true;
|
||||
setHasSupporterKey(hasKey);
|
||||
setContributorClaimUrl(
|
||||
typeof settings.contributorClaimUrl === "string" ? settings.contributorClaimUrl : null
|
||||
);
|
||||
setSupporterPlansUrl(
|
||||
typeof settings.supporterPlansUrl === "string" ? settings.supporterPlansUrl : null
|
||||
);
|
||||
if (hasKey) await syncAndLoad();
|
||||
} catch {
|
||||
setError(t("loadFailed"));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
void load();
|
||||
}, [syncAndLoad, t]);
|
||||
|
||||
const activeOffers = useMemo(() => filterActiveRadarOffers(offers, new Date()), [offers]);
|
||||
|
||||
const formatBenefit = useCallback(
|
||||
(benefit: RadarOfferBenefit): string => {
|
||||
if (benefit.kind === "percent_off") {
|
||||
return `${new Intl.NumberFormat(locale, { maximumFractionDigits: 2 }).format(
|
||||
benefit.basisPoints / 100
|
||||
)}%`;
|
||||
}
|
||||
if (benefit.kind === "credit") {
|
||||
return new Intl.NumberFormat(locale, {
|
||||
style: "currency",
|
||||
currency: benefit.currency,
|
||||
}).format(benefit.amountMinor / 100);
|
||||
}
|
||||
return t("trialDays", { days: benefit.days });
|
||||
},
|
||||
[locale, t]
|
||||
);
|
||||
|
||||
if (flagOff) notFound();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-col gap-3">
|
||||
<Link
|
||||
href="/dashboard/radar"
|
||||
className="text-sm text-text-muted hover:text-text-main transition-colors w-fit"
|
||||
>
|
||||
← {t("backToRadar")}
|
||||
</Link>
|
||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold">{t("title")}</h1>
|
||||
<p className="text-sm text-text-muted mt-1">{t("subtitle")}</p>
|
||||
</div>
|
||||
{hasSupporterKey && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => void syncAndLoad()}
|
||||
disabled={refreshing}
|
||||
className="px-4 py-2 text-sm font-medium rounded-lg border border-violet-500 text-violet-400 hover:bg-violet-500/10 transition-colors disabled:opacity-50"
|
||||
>
|
||||
{refreshing ? t("refreshing") : t("refresh")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{error && <div className="p-3 rounded-lg bg-red-500/10 text-red-400 text-sm">{error}</div>}
|
||||
|
||||
{loading ? (
|
||||
<div className="flex min-h-48 items-center justify-center text-text-muted">
|
||||
{t("loading")}
|
||||
</div>
|
||||
) : !hasSupporterKey ? (
|
||||
<Card>
|
||||
<div className="flex flex-col items-center gap-4 py-8 text-center">
|
||||
<span className="material-symbols-outlined text-4xl text-violet-400">redeem</span>
|
||||
<h2 className="text-xl font-semibold">{t("keyRequiredTitle")}</h2>
|
||||
<p className="max-w-xl text-text-muted">{t("keyRequiredDescription")}</p>
|
||||
<div className="flex flex-col sm:flex-row gap-3">
|
||||
{contributorClaimUrl && (
|
||||
<a
|
||||
href={contributorClaimUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="px-4 py-2 rounded-lg border border-violet-500 text-violet-400 hover:bg-violet-500/10"
|
||||
>
|
||||
{t("contributorButton")}
|
||||
</a>
|
||||
)}
|
||||
{supporterPlansUrl && (
|
||||
<a
|
||||
href={supporterPlansUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="px-4 py-2 rounded-lg bg-violet-500 text-white hover:bg-violet-600"
|
||||
>
|
||||
{t("supporterButton")}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
) : activeOffers.length === 0 ? (
|
||||
<Card>
|
||||
<p className="py-8 text-center text-text-muted">{t("empty")}</p>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
{activeOffers.map((offer) => (
|
||||
<Card key={`${offer.provider}:${offer.id}`}>
|
||||
<div className="flex h-full flex-col gap-4">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<p className="text-xs uppercase tracking-wide text-text-muted">
|
||||
{offer.provider}
|
||||
</p>
|
||||
<h2 className="text-lg font-semibold">
|
||||
{localizeRadarOfferText(offer.title, locale)}
|
||||
</h2>
|
||||
</div>
|
||||
<span
|
||||
className={`rounded-full px-2 py-1 text-xs font-medium ${
|
||||
offer.partner
|
||||
? "bg-violet-500/15 text-violet-300"
|
||||
: "bg-green-500/15 text-green-300"
|
||||
}`}
|
||||
>
|
||||
{offer.partner ? t("partnerBadge") : t("officialBadge")}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p className="text-2xl font-bold text-violet-300">{formatBenefit(offer.benefit)}</p>
|
||||
<p className="text-sm text-text-muted">
|
||||
{localizeRadarOfferText(offer.description, locale)}
|
||||
</p>
|
||||
<div className="text-sm">
|
||||
<span className="font-medium">{t("conditionsLabel")}</span>{" "}
|
||||
<span className="text-text-muted">
|
||||
{localizeRadarOfferText(offer.conditions, locale)}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-text-muted">
|
||||
{offer.validUntil
|
||||
? t("validUntil", {
|
||||
date: new Date(offer.validUntil).toLocaleDateString(locale),
|
||||
})
|
||||
: t("noExpiry")}
|
||||
</p>
|
||||
<a
|
||||
href={offer.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="mt-auto inline-flex w-fit items-center gap-1 text-sm font-medium text-violet-400 hover:underline"
|
||||
>
|
||||
{t("openOffer")}
|
||||
<span className="material-symbols-outlined text-sm">open_in_new</span>
|
||||
</a>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{meta && (
|
||||
<p className="text-xs text-text-muted">
|
||||
{meta.version} · {new Date(meta.fetchedAt).toLocaleString(locale)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
import { useState, useEffect, useCallback, useRef } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { notFound } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import { Card } from "@/shared/components";
|
||||
import { shouldAutoSyncOnOpen } from "@/lib/radar/autoSync";
|
||||
import { isValidSupporterKeyFormat } from "@/lib/radar/supporterKey";
|
||||
import { RadarCatalogTable, type RadarMergedEntry } from "./RadarCatalogTable";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
@@ -18,27 +19,6 @@ interface RadarMeta {
|
||||
fetchedAt: string;
|
||||
}
|
||||
|
||||
interface RadarMergedEntry {
|
||||
provider: string;
|
||||
modelId: string;
|
||||
displayName: string;
|
||||
monthlyTokens: number;
|
||||
creditTokens: number;
|
||||
freeType: string;
|
||||
poolKey: string | null;
|
||||
tos: string;
|
||||
trainsOnPrompts?: boolean;
|
||||
enabled?: boolean;
|
||||
origin: "baseline" | "radar" | "local";
|
||||
disabledBy?: "radar";
|
||||
// Extended feed fields (present when origin=radar)
|
||||
contextWindow?: number | null;
|
||||
capabilities?: { tools: boolean; vision: boolean; thinking: boolean };
|
||||
budget?: { kind: string; tokensPerMonth?: number; poolId?: string };
|
||||
limits?: { rpm: number | null; rpd: number | null; tpm: number | null; tpd: number | null };
|
||||
setup?: { keyUrl: string | null; steps: string[] } | null;
|
||||
}
|
||||
|
||||
type PageState = "flag_off" | "optin_pending" | "empty" | "populated";
|
||||
|
||||
/** D28 — referral links / free credits. Client-side mirror of RadarReferral. */
|
||||
@@ -67,7 +47,7 @@ type RadarTabId = "catalog" | "referrals";
|
||||
export function resolveRadarPageState(
|
||||
flagOn: boolean,
|
||||
optedIn: boolean,
|
||||
hasEntries: boolean,
|
||||
hasEntries: boolean
|
||||
): PageState {
|
||||
if (!flagOn) return "flag_off";
|
||||
if (!optedIn) return "optin_pending";
|
||||
@@ -90,23 +70,6 @@ function relativeTime(isoDate: string): string {
|
||||
return `${days}d ago`;
|
||||
}
|
||||
|
||||
/** Format token count as human-readable. */
|
||||
function formatTokens(n: number): string {
|
||||
if (n === 0) return "rate-only";
|
||||
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
||||
if (n >= 1_000) return `${(n / 1_000).toFixed(0)}K`;
|
||||
return String(n);
|
||||
}
|
||||
|
||||
/** Budget display string. */
|
||||
function budgetLabel(entry: RadarMergedEntry): string {
|
||||
if (entry.budget?.kind === "shared_pool") {
|
||||
return `shared (${formatTokens(entry.budget.tokensPerMonth ?? entry.monthlyTokens)}/mo)`;
|
||||
}
|
||||
if (entry.budget?.kind === "rate_only" || entry.monthlyTokens === 0) return "rate-only";
|
||||
return `${formatTokens(entry.monthlyTokens)}/mo`;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Page Component
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -144,31 +107,34 @@ export default function RadarPage() {
|
||||
const [hasSupporterKey, setHasSupporterKey] = useState(false);
|
||||
const [supporterKeyMasked, setSupporterKeyMasked] = useState<string | null>(null);
|
||||
const [showKeyForm, setShowKeyForm] = useState(false);
|
||||
|
||||
// Fetch catalog
|
||||
const fetchCatalog = useCallback(async () => {
|
||||
setLoading(true);
|
||||
setError("");
|
||||
try {
|
||||
const res = await fetch("/api/radar/catalog");
|
||||
if (res.status === 404) {
|
||||
// Flag off — treat as not found
|
||||
setOptIn(false);
|
||||
setEntries([]);
|
||||
setMeta(null);
|
||||
setLoading(false);
|
||||
return;
|
||||
const fetchCatalog = useCallback(
|
||||
async (showLoading = true) => {
|
||||
if (showLoading) setLoading(true);
|
||||
setError("");
|
||||
try {
|
||||
const res = await fetch("/api/radar/catalog");
|
||||
if (res.status === 404) {
|
||||
// Flag off — treat as not found
|
||||
setOptIn(false);
|
||||
setEntries([]);
|
||||
setMeta(null);
|
||||
if (showLoading) setLoading(false);
|
||||
return;
|
||||
}
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const data = await res.json();
|
||||
setEntries(data.entries || []);
|
||||
setMeta(data.meta || null);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : t("errorLoading"));
|
||||
} finally {
|
||||
if (showLoading) setLoading(false);
|
||||
}
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const data = await res.json();
|
||||
setEntries(data.entries || []);
|
||||
setMeta(data.meta || null);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : t("errorLoading"));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [t]);
|
||||
},
|
||||
[t]
|
||||
);
|
||||
const refreshCatalogSilently = useCallback(() => fetchCatalog(false), [fetchCatalog]);
|
||||
|
||||
// D28 — fetch the referral links section ("Pegue seus créditos grátis").
|
||||
// Best-effort: flag off => 404, no cache => empty shape; either way this
|
||||
@@ -204,7 +170,7 @@ export default function RadarPage() {
|
||||
setOptIn(settingsData.optIn === true);
|
||||
setHasSupporterKey(settingsData.hasSupporterKey === true);
|
||||
setSupporterKeyMasked(
|
||||
typeof settingsData.supporterKeyMasked === "string" ? settingsData.supporterKeyMasked : null,
|
||||
typeof settingsData.supporterKeyMasked === "string" ? settingsData.supporterKeyMasked : null
|
||||
);
|
||||
// F4/T7 — best-effort: keep whatever we already had if the field is
|
||||
// absent (older cached response shape), never fall back to a literal.
|
||||
@@ -334,7 +300,7 @@ export default function RadarPage() {
|
||||
const pageState = resolveRadarPageState(
|
||||
optIn !== false, // if we got a 404, optIn=false => flag off
|
||||
optIn === true,
|
||||
entries.length > 0 && meta !== null,
|
||||
meta !== null
|
||||
);
|
||||
|
||||
// Flag off — render not-found
|
||||
@@ -350,15 +316,41 @@ export default function RadarPage() {
|
||||
<h1 className="text-2xl font-bold">{t("title")}</h1>
|
||||
<p className="text-sm text-text-muted mt-1">{t("subtitle")}</p>
|
||||
</div>
|
||||
{pageState === "populated" && (
|
||||
<button
|
||||
onClick={handleSync}
|
||||
disabled={syncing}
|
||||
className="px-4 py-2 text-sm font-medium rounded-lg border border-violet-500 text-violet-400 hover:bg-violet-500/10 transition-colors disabled:opacity-50"
|
||||
>
|
||||
{syncing ? t("syncing") : t("syncNow")}
|
||||
</button>
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
{(pageState === "empty" || pageState === "populated") && (
|
||||
<Link
|
||||
href="/dashboard/radar/intel"
|
||||
className="px-4 py-2 text-sm font-medium rounded-lg border border-border text-text-main hover:border-violet-500 hover:text-violet-400 transition-colors"
|
||||
>
|
||||
{t("intel")}
|
||||
</Link>
|
||||
)}
|
||||
{(pageState === "empty" || pageState === "populated") && (
|
||||
<Link
|
||||
href="/dashboard/radar/offers"
|
||||
className="px-4 py-2 text-sm font-medium rounded-lg border border-border text-text-main hover:border-violet-500 hover:text-violet-400 transition-colors"
|
||||
>
|
||||
{t("offers")}
|
||||
</Link>
|
||||
)}
|
||||
{(pageState === "empty" || pageState === "populated") && (
|
||||
<Link
|
||||
href="/dashboard/radar/combos"
|
||||
className="px-4 py-2 text-sm font-medium rounded-lg border border-border text-text-main hover:border-violet-500 hover:text-violet-400 transition-colors"
|
||||
>
|
||||
{t("guidedCombos")}
|
||||
</Link>
|
||||
)}
|
||||
{pageState === "populated" && (
|
||||
<button
|
||||
onClick={handleSync}
|
||||
disabled={syncing}
|
||||
className="px-4 py-2 text-sm font-medium rounded-lg border border-violet-500 text-violet-400 hover:bg-violet-500/10 transition-colors disabled:opacity-50"
|
||||
>
|
||||
{syncing ? t("syncing") : t("syncNow")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Feed freshness header */}
|
||||
@@ -379,9 +371,7 @@ export default function RadarPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<div className="p-3 rounded-lg bg-red-500/10 text-red-400 text-sm">{error}</div>
|
||||
)}
|
||||
{error && <div className="p-3 rounded-lg bg-red-500/10 text-red-400 text-sm">{error}</div>}
|
||||
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center min-h-[200px]">
|
||||
@@ -625,98 +615,11 @@ export default function RadarPage() {
|
||||
|
||||
{/* Populated catalog table */}
|
||||
{pageState === "populated" && activeTab === "catalog" && (
|
||||
<Card>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full">
|
||||
<thead>
|
||||
<tr className="text-left text-sm text-text-muted border-b border-border">
|
||||
<th className="pb-3 font-medium">{t("colProvider")}</th>
|
||||
<th className="pb-3 font-medium">{t("colModel")}</th>
|
||||
<th className="pb-3 font-medium">{t("colQuota")}</th>
|
||||
<th className="pb-3 font-medium">{t("colContext")}</th>
|
||||
<th className="pb-3 font-medium">{t("colCapabilities")}</th>
|
||||
<th className="pb-3 font-medium">{t("colTos")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{entries.map((entry) => (
|
||||
<tr
|
||||
key={`${entry.provider}:${entry.modelId}`}
|
||||
className={`border-b border-border/50 last:border-b-0 ${
|
||||
entry.enabled === false ? "opacity-50" : ""
|
||||
}`}
|
||||
>
|
||||
<td className="py-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium">{entry.provider}</span>
|
||||
{entry.origin === "radar" && (
|
||||
<span className="text-[10px] px-1.5 py-0.5 rounded bg-violet-500/10 text-violet-400 font-medium">
|
||||
{t("newBadge")}
|
||||
</span>
|
||||
)}
|
||||
{entry.setup?.keyUrl && (
|
||||
<Link
|
||||
href={`/dashboard/radar/setup?provider=${encodeURIComponent(entry.provider)}`}
|
||||
className="text-xs text-violet-400 hover:underline"
|
||||
title={t("setupGuide")}
|
||||
>
|
||||
⚙
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
{entry.enabled === false && entry.disabledBy === "radar" && (
|
||||
<p className="text-xs text-red-400 mt-0.5">{t("disabledByFeed")}</p>
|
||||
)}
|
||||
</td>
|
||||
<td className="py-3 text-text-muted text-sm font-mono truncate max-w-[200px]">
|
||||
{entry.displayName}
|
||||
</td>
|
||||
<td className="py-3 text-sm">{budgetLabel(entry)}</td>
|
||||
<td className="py-3 text-sm text-text-muted">
|
||||
{entry.contextWindow
|
||||
? `${(entry.contextWindow / 1000).toFixed(0)}K`
|
||||
: "—"}
|
||||
</td>
|
||||
<td className="py-3">
|
||||
<div className="flex gap-1">
|
||||
{entry.capabilities?.tools && (
|
||||
<span className="text-[10px] px-1.5 py-0.5 rounded bg-blue-500/10 text-blue-400">
|
||||
{t("capTools")}
|
||||
</span>
|
||||
)}
|
||||
{entry.capabilities?.vision && (
|
||||
<span className="text-[10px] px-1.5 py-0.5 rounded bg-purple-500/10 text-purple-400">
|
||||
{t("capVision")}
|
||||
</span>
|
||||
)}
|
||||
{entry.capabilities?.thinking && (
|
||||
<span className="text-[10px] px-1.5 py-0.5 rounded bg-amber-500/10 text-amber-400">
|
||||
{t("capThinking")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="py-3">
|
||||
<span
|
||||
className={`text-xs px-2 py-1 rounded ${
|
||||
entry.tos === "ok"
|
||||
? "bg-green-500/10 text-green-400"
|
||||
: entry.tos === "caution"
|
||||
? "bg-yellow-500/10 text-yellow-400"
|
||||
: entry.tos === "avoid"
|
||||
? "bg-red-500/10 text-red-400"
|
||||
: "bg-gray-500/10 text-gray-400"
|
||||
}`}
|
||||
>
|
||||
{entry.tos}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</Card>
|
||||
<RadarCatalogTable
|
||||
entries={entries}
|
||||
refreshCatalog={refreshCatalogSilently}
|
||||
onError={setError}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Card } from "@/shared/components";
|
||||
import {
|
||||
firstProviderConnectionId,
|
||||
providerConnectionsRequestUrl,
|
||||
providerSetupConnectionUrl,
|
||||
type RadarSetupConnection,
|
||||
} from "@/lib/radar/setupConnections";
|
||||
import type { RadarLocalizedText } from "@/lib/radar/feedSchema";
|
||||
@@ -132,13 +133,13 @@ export default function RadarSetupPage() {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
if (res.ok) {
|
||||
const data = await res.json().catch(() => null);
|
||||
if (res.ok && data?.valid === true) {
|
||||
setTestResult({ ok: true, message: t("testSuccess") });
|
||||
} else {
|
||||
const data = await res.json().catch(() => null);
|
||||
setTestResult({
|
||||
ok: false,
|
||||
message: data?.error?.message || t("testFailed"),
|
||||
message: t("testFailed"),
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
@@ -236,14 +237,6 @@ export default function RadarSetupPage() {
|
||||
<Card>
|
||||
<div className="text-center py-8 text-text-muted">
|
||||
<p>{t("noGuide")}</p>
|
||||
<a
|
||||
href={`https://${provider}.com`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-violet-400 hover:underline mt-2 inline-block"
|
||||
>
|
||||
{t("visitDocs")}
|
||||
</a>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
@@ -276,7 +269,7 @@ export default function RadarSetupPage() {
|
||||
<h2 className="font-semibold">{t("addConnection")}</h2>
|
||||
<p className="text-sm text-text-muted">{t("addConnectionDescription")}</p>
|
||||
<Link
|
||||
href={`/dashboard/providers?add=${encodeURIComponent(provider)}`}
|
||||
href={providerSetupConnectionUrl(provider)}
|
||||
className="text-violet-400 hover:underline text-sm"
|
||||
>
|
||||
{t("addConnectionLink")}
|
||||
|
||||
@@ -185,7 +185,7 @@ export default function ResilienceConnectionsClient() {
|
||||
color: "var(--color-warning)",
|
||||
}}
|
||||
>
|
||||
{t("degraded", {
|
||||
{t("degraded.message", {
|
||||
sources: data.meta.degraded.map((s) => t(`degraded.source.${s}`)).join(", "),
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
applyItemOrder,
|
||||
normalizeHiddenSidebarItems,
|
||||
HIDEABLE_SIDEBAR_ITEM_IDS,
|
||||
resolveRuntimeSidebarSections,
|
||||
type HideableSidebarItemId,
|
||||
type SidebarItemId,
|
||||
type SidebarSectionId,
|
||||
@@ -265,7 +266,9 @@ function ItemRow({ item, hiddenSet, onToggleItem, getLabel }: ItemRowProps) {
|
||||
<span className="material-symbols-outlined text-[16px] text-text-muted/50 shrink-0">
|
||||
{item.icon}
|
||||
</span>
|
||||
<p className="font-medium truncate">{getLabel(item.i18nKey, item.id)}</p>
|
||||
<p className="font-medium truncate">
|
||||
{getLabel(item.i18nKey, item.labelFallback ?? item.id)}
|
||||
</p>
|
||||
</div>
|
||||
{isProtected ? (
|
||||
<span
|
||||
@@ -327,8 +330,8 @@ function GroupRow({
|
||||
</span>
|
||||
</button>
|
||||
<span className="text-xs text-text-muted/40">
|
||||
{group.items.filter((i) => !isHideableSidebarItemId(i.id) || !hiddenSet.has(i.id)).length}/
|
||||
{group.items.length}
|
||||
{group.items.filter((i) => !isHideableSidebarItemId(i.id) || !hiddenSet.has(i.id)).length}
|
||||
/{group.items.length}
|
||||
</span>
|
||||
{canToggleSeparator && (
|
||||
<div className="flex items-center gap-2 border-l border-border/60 pl-3">
|
||||
@@ -349,7 +352,9 @@ function GroupRow({
|
||||
<span className="material-symbols-outlined text-[14px] text-text-muted/40 shrink-0">
|
||||
{item.icon}
|
||||
</span>
|
||||
<p className="text-sm font-medium truncate">{getLabel(item.i18nKey, item.id)}</p>
|
||||
<p className="text-sm font-medium truncate">
|
||||
{getLabel(item.i18nKey, item.labelFallback ?? item.id)}
|
||||
</p>
|
||||
</div>
|
||||
<GroupItemVisibilityControl
|
||||
item={item}
|
||||
@@ -391,6 +396,7 @@ export default function SidebarTab() {
|
||||
const [activePreset, setActivePreset] = useState<SidebarPresetId | null>(null);
|
||||
const [confirmPreset, setConfirmPreset] = useState<SidebarPresetId | null>(null);
|
||||
const [showDebug, setShowDebug] = useState(false);
|
||||
const [radarAdminUrl, setRadarAdminUrl] = useState<unknown>(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/api/settings")
|
||||
@@ -412,6 +418,7 @@ export default function SidebarTab() {
|
||||
);
|
||||
setActivePreset(data?.[SIDEBAR_PRESET_KEY] ?? null);
|
||||
setShowDebug(data?.debugMode === true);
|
||||
setRadarAdminUrl(data?.radarAdminUrl ?? null);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(() => setLoading(false));
|
||||
@@ -458,9 +465,9 @@ export default function SidebarTab() {
|
||||
patch({ [HIDDEN_SIDEBAR_GROUP_LABELS_SETTING_KEY]: next, [SIDEBAR_PRESET_KEY]: null });
|
||||
};
|
||||
|
||||
const visibleSections = SIDEBAR_SECTIONS.filter(
|
||||
(s) => s.visibility !== "debug" || showDebug
|
||||
);
|
||||
const visibleSections = resolveRuntimeSidebarSections(SIDEBAR_SECTIONS, {
|
||||
radarAdminUrl,
|
||||
}).filter((s) => s.visibility !== "debug" || showDebug);
|
||||
|
||||
const orderedSections = applySectionOrder(visibleSections, sectionOrder).map((s) => ({
|
||||
...s,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { getSettings } from "@/lib/localDb";
|
||||
import HomePageClient from "../dashboard/HomePageClient";
|
||||
import BootstrapBanner from "../dashboard/BootstrapBanner";
|
||||
import KimiSponsorBanner from "../dashboard/KimiSponsorBanner";
|
||||
import NewsBanner from "../dashboard/NewsBanner";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -18,6 +19,7 @@ export default async function HomePage() {
|
||||
<>
|
||||
{isBootstrapped && <BootstrapBanner />}
|
||||
<KimiSponsorBanner />
|
||||
<NewsBanner />
|
||||
<HomePageClient machineId={machineId} />
|
||||
</>
|
||||
);
|
||||
|
||||
42
src/app/api/radar/intel/route.ts
Normal file
42
src/app/api/radar/intel/route.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/** GET the verified local Radar Intel cache. Never proxies the private service. */
|
||||
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { buildErrorBody, sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
|
||||
|
||||
import { getRadarIntel } from "@/lib/radar";
|
||||
import { isAuthenticated } from "@/shared/utils/apiAuth";
|
||||
import { CORS_HEADERS, handleCorsOptions } from "@/shared/utils/cors";
|
||||
import { isFeatureFlagEnabled } from "@/shared/utils/featureFlags";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
export const revalidate = 0;
|
||||
|
||||
export async function OPTIONS() {
|
||||
return handleCorsOptions();
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
if (!isFeatureFlagEnabled("RADAR_ENABLED")) {
|
||||
return NextResponse.json(buildErrorBody(404, "Not found"), {
|
||||
status: 404,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
if (!(await isAuthenticated(request))) {
|
||||
return NextResponse.json(buildErrorBody(401, "Unauthorized"), {
|
||||
status: 401,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
try {
|
||||
return NextResponse.json(getRadarIntel(), {
|
||||
headers: { ...CORS_HEADERS, "Cache-Control": "no-store" },
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
return NextResponse.json(
|
||||
buildErrorBody(500, sanitizeErrorMessage(error) || "Failed to load Radar Intel"),
|
||||
{ status: 500, headers: CORS_HEADERS }
|
||||
);
|
||||
}
|
||||
}
|
||||
49
src/app/api/radar/intel/sync/route.ts
Normal file
49
src/app/api/radar/intel/sync/route.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/** POST a server-side Radar Intel sync. The browser never receives the supporter key. */
|
||||
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { buildErrorBody, sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
|
||||
|
||||
import { syncRadarIntel } from "@/lib/radar/intelSync";
|
||||
import { isAuthenticated } from "@/shared/utils/apiAuth";
|
||||
import { CORS_HEADERS, handleCorsOptions } from "@/shared/utils/cors";
|
||||
import { isFeatureFlagEnabled } from "@/shared/utils/featureFlags";
|
||||
import { radarSyncBodyError, validateRadarSyncBody } from "../../syncRequest";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
export const revalidate = 0;
|
||||
|
||||
export async function OPTIONS() {
|
||||
return handleCorsOptions();
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
if (!isFeatureFlagEnabled("RADAR_ENABLED")) {
|
||||
return NextResponse.json(buildErrorBody(404, "Not found"), {
|
||||
status: 404,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
if (!(await isAuthenticated(request))) {
|
||||
return NextResponse.json(buildErrorBody(401, "Unauthorized"), {
|
||||
status: 401,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
|
||||
const bodyError = radarSyncBodyError(await validateRadarSyncBody(request));
|
||||
if (bodyError) {
|
||||
return NextResponse.json(buildErrorBody(bodyError.status, bodyError.message), {
|
||||
status: bodyError.status,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
try {
|
||||
return NextResponse.json(await syncRadarIntel(), { headers: CORS_HEADERS });
|
||||
} catch (error: unknown) {
|
||||
return NextResponse.json(
|
||||
buildErrorBody(500, sanitizeErrorMessage(error) || "Radar Intel sync failed"),
|
||||
{ status: 500, headers: CORS_HEADERS }
|
||||
);
|
||||
}
|
||||
}
|
||||
165
src/app/api/radar/local-model-state/route.ts
Normal file
165
src/app/api/radar/local-model-state/route.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* Local-only Radar model overrides and tombstones.
|
||||
*
|
||||
* The browser never sends these settings to the private Radar server. The
|
||||
* route is management-authenticated and exists only while RADAR_ENABLED is on.
|
||||
*/
|
||||
import { NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { buildErrorBody, sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
|
||||
import {
|
||||
clearRadarLocalModelOverride,
|
||||
listRadarLocalModelState,
|
||||
setRadarLocalModelOverride,
|
||||
setRadarModelTombstone,
|
||||
} from "@/lib/db/radar";
|
||||
import { isAuthenticated } from "@/shared/utils/apiAuth";
|
||||
import { CORS_HEADERS, handleCorsOptions } from "@/shared/utils/cors";
|
||||
import { isFeatureFlagEnabled } from "@/shared/utils/featureFlags";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
export const revalidate = 0;
|
||||
|
||||
const providerSchema = z
|
||||
.string()
|
||||
.trim()
|
||||
.regex(/^[a-z0-9][a-z0-9._-]{0,99}$/i);
|
||||
const modelIdSchema = z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.max(200)
|
||||
.refine((value) => !/[\u0000-\u001f\u007f]/.test(value));
|
||||
const identityShape = { provider: providerSchema, modelId: modelIdSchema };
|
||||
|
||||
const overrideSchema = z
|
||||
.object({
|
||||
...identityShape,
|
||||
displayName: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.max(160)
|
||||
.refine((value) => !/[\u0000-\u001f\u007f]/.test(value))
|
||||
.nullable()
|
||||
.optional(),
|
||||
enabled: z.boolean().nullable().optional(),
|
||||
})
|
||||
.strict()
|
||||
.refine(
|
||||
(value) =>
|
||||
Object.prototype.hasOwnProperty.call(value, "displayName") ||
|
||||
Object.prototype.hasOwnProperty.call(value, "enabled")
|
||||
);
|
||||
|
||||
const tombstoneSchema = z.object({ ...identityShape, tombstoned: z.boolean() }).strict();
|
||||
const identitySchema = z.object(identityShape).strict();
|
||||
|
||||
function json(body: unknown, status = 200): NextResponse {
|
||||
return NextResponse.json(body, {
|
||||
status,
|
||||
headers: { ...CORS_HEADERS, "Cache-Control": "no-store" },
|
||||
});
|
||||
}
|
||||
|
||||
function error(status: number, message: string): NextResponse {
|
||||
return json(buildErrorBody(status, message), status);
|
||||
}
|
||||
|
||||
async function authorize(request: Request): Promise<NextResponse | null> {
|
||||
if (!isFeatureFlagEnabled("RADAR_ENABLED")) return error(404, "Not found");
|
||||
if (!(await isAuthenticated(request))) return error(401, "Unauthorized");
|
||||
return null;
|
||||
}
|
||||
|
||||
async function readJson(request: Request): Promise<unknown | null> {
|
||||
try {
|
||||
return await request.json();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function stateResponse(): NextResponse {
|
||||
return json({ states: listRadarLocalModelState() });
|
||||
}
|
||||
|
||||
function internalError(cause: unknown): NextResponse {
|
||||
return error(500, sanitizeErrorMessage(cause) || "Failed to update Radar local state");
|
||||
}
|
||||
|
||||
export async function OPTIONS(): Promise<Response> {
|
||||
return handleCorsOptions();
|
||||
}
|
||||
|
||||
export async function GET(request: Request): Promise<NextResponse> {
|
||||
const authError = await authorize(request);
|
||||
if (authError) return authError;
|
||||
try {
|
||||
return stateResponse();
|
||||
} catch (cause: unknown) {
|
||||
return internalError(cause);
|
||||
}
|
||||
}
|
||||
|
||||
export async function PATCH(request: Request): Promise<NextResponse> {
|
||||
const authError = await authorize(request);
|
||||
if (authError) return authError;
|
||||
|
||||
const parsed = overrideSchema.safeParse(await readJson(request));
|
||||
if (!parsed.success) return error(400, "Invalid Radar local override");
|
||||
|
||||
try {
|
||||
const { provider, modelId, displayName, enabled } = parsed.data;
|
||||
const patch: { displayName?: string | null; enabled?: boolean | null } = {};
|
||||
if (Object.prototype.hasOwnProperty.call(parsed.data, "displayName")) {
|
||||
patch.displayName = displayName;
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(parsed.data, "enabled")) patch.enabled = enabled;
|
||||
if (!setRadarLocalModelOverride(provider, modelId, patch)) {
|
||||
return error(400, "Invalid Radar local override");
|
||||
}
|
||||
return stateResponse();
|
||||
} catch (cause: unknown) {
|
||||
return internalError(cause);
|
||||
}
|
||||
}
|
||||
|
||||
export async function PUT(request: Request): Promise<NextResponse> {
|
||||
const authError = await authorize(request);
|
||||
if (authError) return authError;
|
||||
|
||||
const parsed = tombstoneSchema.safeParse(await readJson(request));
|
||||
if (!parsed.success) return error(400, "Invalid Radar tombstone");
|
||||
|
||||
try {
|
||||
const { provider, modelId, tombstoned } = parsed.data;
|
||||
if (!setRadarModelTombstone(provider, modelId, tombstoned)) {
|
||||
return error(400, "Invalid Radar tombstone");
|
||||
}
|
||||
return stateResponse();
|
||||
} catch (cause: unknown) {
|
||||
return internalError(cause);
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(request: Request): Promise<NextResponse> {
|
||||
const authError = await authorize(request);
|
||||
if (authError) return authError;
|
||||
|
||||
const url = new URL(request.url);
|
||||
const parsed = identitySchema.safeParse({
|
||||
provider: url.searchParams.get("provider"),
|
||||
modelId: url.searchParams.get("modelId"),
|
||||
});
|
||||
if (!parsed.success) return error(400, "provider and modelId are required");
|
||||
|
||||
try {
|
||||
if (!clearRadarLocalModelOverride(parsed.data.provider, parsed.data.modelId)) {
|
||||
return error(400, "Invalid Radar local override");
|
||||
}
|
||||
return stateResponse();
|
||||
} catch (cause: unknown) {
|
||||
return internalError(cause);
|
||||
}
|
||||
}
|
||||
41
src/app/api/radar/offers/route.ts
Normal file
41
src/app/api/radar/offers/route.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/** GET the verified local Radar offers cache. Never proxies the private service. */
|
||||
|
||||
import { NextResponse } from "next/server";
|
||||
import { buildErrorBody, sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
|
||||
import { getRadarOffers } from "@/lib/radar";
|
||||
import { isAuthenticated } from "@/shared/utils/apiAuth";
|
||||
import { CORS_HEADERS, handleCorsOptions } from "@/shared/utils/cors";
|
||||
import { isFeatureFlagEnabled } from "@/shared/utils/featureFlags";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
export const revalidate = 0;
|
||||
|
||||
export async function OPTIONS() {
|
||||
return handleCorsOptions();
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
if (!isFeatureFlagEnabled("RADAR_ENABLED")) {
|
||||
return NextResponse.json(buildErrorBody(404, "Not found"), {
|
||||
status: 404,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
if (!(await isAuthenticated(request))) {
|
||||
return NextResponse.json(buildErrorBody(401, "Unauthorized"), {
|
||||
status: 401,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
return NextResponse.json(getRadarOffers(), {
|
||||
headers: { ...CORS_HEADERS, "Cache-Control": "no-store" },
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
return NextResponse.json(
|
||||
buildErrorBody(500, sanitizeErrorMessage(error) || "Failed to load Radar offers"),
|
||||
{ status: 500, headers: CORS_HEADERS }
|
||||
);
|
||||
}
|
||||
}
|
||||
48
src/app/api/radar/offers/sync/route.ts
Normal file
48
src/app/api/radar/offers/sync/route.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/** POST a server-side Radar offers sync. The browser never receives the supporter key. */
|
||||
|
||||
import { NextResponse } from "next/server";
|
||||
import { buildErrorBody, sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
|
||||
import { syncRadarOffers } from "@/lib/radar/offersSync";
|
||||
import { isAuthenticated } from "@/shared/utils/apiAuth";
|
||||
import { CORS_HEADERS, handleCorsOptions } from "@/shared/utils/cors";
|
||||
import { isFeatureFlagEnabled } from "@/shared/utils/featureFlags";
|
||||
import { radarSyncBodyError, validateRadarSyncBody } from "../../syncRequest";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
export const revalidate = 0;
|
||||
|
||||
export async function OPTIONS() {
|
||||
return handleCorsOptions();
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
if (!isFeatureFlagEnabled("RADAR_ENABLED")) {
|
||||
return NextResponse.json(buildErrorBody(404, "Not found"), {
|
||||
status: 404,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
if (!(await isAuthenticated(request))) {
|
||||
return NextResponse.json(buildErrorBody(401, "Unauthorized"), {
|
||||
status: 401,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
|
||||
const bodyError = radarSyncBodyError(await validateRadarSyncBody(request));
|
||||
if (bodyError) {
|
||||
return NextResponse.json(buildErrorBody(bodyError.status, bodyError.message), {
|
||||
status: bodyError.status,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
return NextResponse.json(await syncRadarOffers(), { headers: CORS_HEADERS });
|
||||
} catch (error: unknown) {
|
||||
return NextResponse.json(
|
||||
buildErrorBody(500, sanitizeErrorMessage(error) || "Radar offers sync failed"),
|
||||
{ status: 500, headers: CORS_HEADERS }
|
||||
);
|
||||
}
|
||||
}
|
||||
70
src/app/api/radar/status/route.ts
Normal file
70
src/app/api/radar/status/route.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
/** Read-only aggregate status of local Radar state. */
|
||||
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { buildErrorBody, sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
|
||||
|
||||
import {
|
||||
getRadarCache,
|
||||
getRadarIntelCache,
|
||||
getRadarOffersCache,
|
||||
getRadarReferralsCache,
|
||||
getRadarSettings,
|
||||
} from "@/lib/db/radar";
|
||||
import { isAuthenticated } from "@/shared/utils/apiAuth";
|
||||
import { CORS_HEADERS, handleCorsOptions } from "@/shared/utils/cors";
|
||||
import { isFeatureFlagEnabled } from "@/shared/utils/featureFlags";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
export const revalidate = 0;
|
||||
|
||||
export async function OPTIONS() {
|
||||
return handleCorsOptions();
|
||||
}
|
||||
|
||||
function cacheStatus(
|
||||
cache: { version?: string; generatedAt?: string; tier: string; fetchedAt: string } | null
|
||||
) {
|
||||
if (!cache) return { available: false };
|
||||
return {
|
||||
available: true,
|
||||
version: cache.version ?? cache.generatedAt,
|
||||
tier: cache.tier,
|
||||
fetchedAt: cache.fetchedAt,
|
||||
};
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
if (!isFeatureFlagEnabled("RADAR_ENABLED")) {
|
||||
return NextResponse.json(buildErrorBody(404, "Not found"), {
|
||||
status: 404,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
if (!(await isAuthenticated(request))) {
|
||||
return NextResponse.json(buildErrorBody(401, "Unauthorized"), {
|
||||
status: 401,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
try {
|
||||
const settings = getRadarSettings();
|
||||
return NextResponse.json(
|
||||
{
|
||||
settings: { optIn: settings.optIn, hasSupporterKey: settings.supporterKey !== null },
|
||||
feeds: {
|
||||
catalog: cacheStatus(getRadarCache()),
|
||||
referrals: cacheStatus(getRadarReferralsCache()),
|
||||
offers: cacheStatus(getRadarOffersCache()),
|
||||
intel: cacheStatus(getRadarIntelCache()),
|
||||
},
|
||||
},
|
||||
{ headers: { ...CORS_HEADERS, "Cache-Control": "no-store" } }
|
||||
);
|
||||
} catch (error: unknown) {
|
||||
return NextResponse.json(
|
||||
buildErrorBody(500, sanitizeErrorMessage(error) || "Failed to load Radar status"),
|
||||
{ status: 500, headers: CORS_HEADERS }
|
||||
);
|
||||
}
|
||||
}
|
||||
55
src/app/api/radar/sync-all/route.ts
Normal file
55
src/app/api/radar/sync-all/route.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/** Aggregate local trigger for every Radar feed sync. */
|
||||
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { buildErrorBody, sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
|
||||
|
||||
import { syncRadarIntel } from "@/lib/radar/intelSync";
|
||||
import { syncRadarOffers } from "@/lib/radar/offersSync";
|
||||
import { syncRadarReferrals } from "@/lib/radar/referralsSync";
|
||||
import { syncRadar } from "@/lib/radar/sync";
|
||||
import { isAuthenticated } from "@/shared/utils/apiAuth";
|
||||
import { CORS_HEADERS, handleCorsOptions } from "@/shared/utils/cors";
|
||||
import { isFeatureFlagEnabled } from "@/shared/utils/featureFlags";
|
||||
import { radarSyncBodyError, validateRadarSyncBody } from "../syncRequest";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
export const revalidate = 0;
|
||||
|
||||
export async function OPTIONS() {
|
||||
return handleCorsOptions();
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
if (!isFeatureFlagEnabled("RADAR_ENABLED")) {
|
||||
return NextResponse.json(buildErrorBody(404, "Not found"), {
|
||||
status: 404,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
if (!(await isAuthenticated(request))) {
|
||||
return NextResponse.json(buildErrorBody(401, "Unauthorized"), {
|
||||
status: 401,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
const bodyError = radarSyncBodyError(await validateRadarSyncBody(request));
|
||||
if (bodyError) {
|
||||
return NextResponse.json(buildErrorBody(bodyError.status, bodyError.message), {
|
||||
status: bodyError.status,
|
||||
headers: CORS_HEADERS,
|
||||
});
|
||||
}
|
||||
try {
|
||||
const catalog = await syncRadar();
|
||||
const referrals = await syncRadarReferrals();
|
||||
const offers = await syncRadarOffers();
|
||||
const intel = await syncRadarIntel();
|
||||
return NextResponse.json({ catalog, referrals, offers, intel }, { headers: CORS_HEADERS });
|
||||
} catch (error: unknown) {
|
||||
return NextResponse.json(
|
||||
buildErrorBody(500, sanitizeErrorMessage(error) || "Radar aggregate sync failed"),
|
||||
{ status: 500, headers: CORS_HEADERS }
|
||||
);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user