diff --git a/.env.example b/.env.example index c809f7653c..d193fa35a0 100644 --- a/.env.example +++ b/.env.example @@ -1033,6 +1033,10 @@ PROVIDER_LIMITS_SYNC_SPACING_MS=1500 # Used by: src/lib/db/core.ts::getDbHealthCheckIntervalMs(). #OMNIROUTE_DB_HEALTHCHECK_INTERVAL_MS=21600000 +# WAL truncate cadence override (ms). Set to 0 to disable. Default: 21600000 (6h). +# Used by: src/lib/db/core.ts::getWalTruncateIntervalMs(). +#OMNIROUTE_WAL_TRUNCATE_INTERVAL_MS=21600000 + # Skip the Redis-backed auth cache used by API key lookups (forces DB reads). # Used by: src/lib/db/apiKeys.ts. Set to 1 to disable. Default: enabled. #OMNIROUTE_DISABLE_REDIS_AUTH_CACHE=0 diff --git a/AGENTS.md b/AGENTS.md index b1bcfebafd..4472c2fa5e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,7 +46,7 @@ Repository map and Reference Documentation sections below. ## Project at a Glance -**OmniRoute** — unified AI proxy/router. One endpoint, 341 LLM providers, auto-fallback. +**OmniRoute** — unified AI proxy/router. One endpoint, 342 LLM providers, auto-fallback. | Layer | Location | Purpose | | ------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/README.md b/README.md index d04278cab3..fd13437fc9 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ # 🚀 OmniRoute — The Free AI Gateway -OmniRoute — Never stop coding. Every AI tool → 341 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot & Antigravity into FREE Claude / GPT / Gemini with auto-fallback. RTK + Caveman stacked compression saves 15–95% tokens (~89% avg) — never hit limits. 341 AI providers · 90+ free tiers · ~1.51B free tokens/mo · 19 routing strategies · $0 to start. +OmniRoute — Never stop coding. Every AI tool → 342 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot & Antigravity into FREE Claude / GPT / Gemini with auto-fallback. RTK + Caveman stacked compression saves 15–95% tokens (~89% avg) — never hit limits. 342 AI providers · 90+ free tiers · ~1.51B free tokens/mo · 19 routing strategies · $0 to start. @@ -63,7 +63,7 @@ | | v3.8.49 | **v3.8.50** | `v3.8.51+` | | ------------------------- | :-----: | :---------: | :---------: | -| 🌐 Providers | 290 | **341** | more queued | +| 🌐 Providers | 290 | **342** | more queued | | 🧠 Documented models | 1185 | **1202** | — | | 🖼️ Modality Bridge | — | 🆕 vision | video | | 📡 Radar free catalog | — | 🆕 opt-in | — | @@ -101,7 +101,7 @@ ⚙️ Features 🎯 Combos - 🌐 Providers + 🌐 Providers 🔌 CLI & MCP @@ -210,7 +210,7 @@ curl http://localhost:20128/v1/chat/completions \ -The Promise — One endpoint. 341 providers. Never stop building — OmniRoute picks the cheapest one that works. Six pillars: Never hit limits (auto-fallback across 341 providers in milliseconds, zero downtime) · Save up to 95% tokens (RTK + Caveman stacked compression cuts 15–95%, ~89% avg on tool-heavy sessions) · $0 to start (90+ free tiers, 56 free forever — no card needed) · Every tool works (33 coding agents through one config) · One endpoint (OpenAI ↔ Claude ↔ Gemini ↔ Responses API at /v1) · Production-grade (circuit breakers, TLS stealth, MCP 109 tools, A2A, memory, guardrails, evals — 25,000+ tests). +The Promise — One endpoint. 342 providers. Never stop building — OmniRoute picks the cheapest one that works. Six pillars: Never hit limits (auto-fallback across 342 providers in milliseconds, zero downtime) · Save up to 95% tokens (RTK + Caveman stacked compression cuts 15–95%, ~89% avg on tool-heavy sessions) · $0 to start (90+ free tiers, 56 free forever — no card needed) · Every tool works (33 coding agents through one config) · One endpoint (OpenAI ↔ Claude ↔ Gemini ↔ Responses API at /v1) · Production-grade (circuit breakers, TLS stealth, MCP 109 tools, A2A, memory, guardrails, evals — 25,000+ tests).

@@ -461,7 +461,7 @@ All **19** strategies — mix & match per combo step: -What sets OmniRoute apart — comparison table vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 341 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, built-in MCP server with 109 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA, 43 i18n UI locales, 100% MIT self-hosted. OmniRoute is the only one with the full set; competitors show a mix of checks, partials and crosses. Verified from each project's docs. +What sets OmniRoute apart — comparison table vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 342 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. 📊 Full methodology & per-feature detail vs 9router, OpenRouter, CLIProxyAPI & LiteLLM → [`docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md`](docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md) @@ -559,7 +559,7 @@ the current catalog at **[radar.omniroute.online/planos](https://radar.omniroute - **🖼️ New endpoints** — `/v1/ocr` (Mistral OCR) and `/v1/audio/translations` (Whisper-style) round out the media surface. → [API Reference](docs/reference/API_REFERENCE.md) - **🎨 Image / video / audio generation** — one API for media: xAI Grok Imagine & Novita AI video, ComfyUI, Freepik, Adobe Firefly, Microsoft Designer, Segmind, EdgeTTS. → [API Reference](docs/reference/API_REFERENCE.md) - **🌍 Deployment & ops** — reverse-proxy `basePath`, browser-language auto-detect, per-key device tracking, root-less MITM trust, zh-TW localization. → [Environment](docs/reference/ENVIRONMENT.md) -- **🤝 More providers & agents** — Cursor Cloud Agent, Grok Build (xAI) with browser + OAuth login, Ollama first-class card, Claude Opus 5 & Sonnet 5, Kimi official partnership (Code/Web/Moonshot), Zed, Requesty, SenseNova, Yuanbao, Agnes AI… and a refreshed **341-provider catalog**. → [Providers](docs/reference/PROVIDER_REFERENCE.md) +- **🤝 More providers & agents** — Cursor Cloud Agent, Grok Build (xAI) with browser + OAuth login, Ollama first-class card, Claude Opus 5 & Sonnet 5, Kimi official partnership (Code/Web/Moonshot), Zed, Requesty, SenseNova, Yuanbao, Agnes AI… and a refreshed **342-provider catalog**. → [Providers](docs/reference/PROVIDER_REFERENCE.md) - **📡 Routing transparency** — every response carries an `X-OmniRoute-Decision` header naming the strategy/provider/latency that served it, a new `cache-optimized` combo strategy + Auto-Combo `cacheAffinity` factor route repeat requests back to the connection holding the cached prefix, and a read-only `/v1/auto-combo/{channel}/candidates` endpoint exposes an `auto/*` channel's live candidate pool. → [Auto-Combo](docs/routing/AUTO-COMBO.md) - **⚡ Local performance & infra** — one-click local Redis, Cloudflare Workers / Deno Deploy relay deployers, Bifrost & Mux as supervised embedded services. → [Embedded Services](docs/frameworks/EMBEDDED-SERVICES.md) @@ -642,11 +642,11 @@ of your shell history. → [CLI Integrations](docs/guides/CLI-INTEGRATIONS.md)
-## 🌐 341 AI Providers — 90+ Free +## 🌐 342 AI Providers — 90+ Free
-> The most complete catalog of any open-source router: **341 providers**, **90+ with a free tier**, **56 free forever**. +> The most complete catalog of any open-source router: **342 providers**, **90+ with a free tier**, **56 free forever**.
diff --git a/changelog.d/features/10729-cursor-api-key-and-cli-passthrough.md b/changelog.d/features/10729-cursor-api-key-and-cli-passthrough.md new file mode 100644 index 0000000000..96094ffff1 --- /dev/null +++ b/changelog.d/features/10729-cursor-api-key-and-cli-passthrough.md @@ -0,0 +1 @@ +- **feat(providers):** new `cursor-api` provider (card "Cursor API", alias `cua`): connect a Cursor user API key (`crsr_…`) and route `cursor-api/` through the existing Cursor agent executor (the key is exchanged for a 1h session token and cached), plus a `/api/cursor-cli/*` passthrough so the Cursor CLI itself runs through OmniRoute (`CURSOR_API_ENDPOINT=http:///api/cursor-cli`, `CURSOR_API_KEY=`) with every RPC attributed and logged. The IDE `cursor` provider is unchanged. (#10729) diff --git a/changelog.d/features/10771-health-root-endpoint.md b/changelog.d/features/10771-health-root-endpoint.md new file mode 100644 index 0000000000..a367bbce78 --- /dev/null +++ b/changelog.d/features/10771-health-root-endpoint.md @@ -0,0 +1 @@ +- **feat(api):** `GET /api/health` now answers `{ status, timestamp }` without a key. Until now the path had no route, so the management-auth boundary answered first with a 401 — indistinguishable from a wrong key or an unknown route, which left Docker HEALTHCHECKs and Kubernetes probes unable to tell "down" from "misconfigured". Kept deliberately minimal: version, uptime and memory stay behind the authenticated `/api/monitoring/health` ([#PRNUM](https://github.com/diegosouzapw/OmniRoute/pull/10771)). diff --git a/changelog.d/features/10783-task-routing-configurable-patterns.md b/changelog.d/features/10783-task-routing-configurable-patterns.md new file mode 100644 index 0000000000..e5c37c390a --- /dev/null +++ b/changelog.d/features/10783-task-routing-configurable-patterns.md @@ -0,0 +1 @@ +- feat(routing): make Task-Aware Smart Routing's detection patterns operator-configurable via `settings.taskRouting.patternOverrides` (`PUT /api/settings/task-routing`) — the built-in patterns are English-only, so a non-English dashboard had no recourse short of turning detection off entirely; an override now replaces the pattern list for one task type without touching the rest (#10783) diff --git a/changelog.d/features/kimi-coding-extra-usage.md b/changelog.d/features/kimi-coding-extra-usage.md new file mode 100644 index 0000000000..766ec1020c --- /dev/null +++ b/changelog.d/features/kimi-coding-extra-usage.md @@ -0,0 +1 @@ +- **feat(usage):** show Kimi Coding's fixed-order Code 5-hour/7-day quota windows plus Extra Usage status, balance, monthly spend/limit, and the official Additional Credits link on Dashboard → Quota cards. diff --git a/changelog.d/fixes/10732-copilot-m365-invocation-refresh.md b/changelog.d/fixes/10732-copilot-m365-invocation-refresh.md new file mode 100644 index 0000000000..acbfbbe693 --- /dev/null +++ b/changelog.d/fixes/10732-copilot-m365-invocation-refresh.md @@ -0,0 +1 @@ +- **fix(providers):** copilot-m365-web chat turns no longer surface as `(empty response)` — the type:4 invocation is aligned with the 2026-08 wire shape and now carries its type:1 Metrics follow-up in the same socket write, and the access token pre-flight-refreshes from a stored refresh_token instead of requiring a DevTools re-capture every ~75 minutes ([#10732](https://github.com/diegosouzapw/OmniRoute/pull/10732) — thanks @acc0mplish) diff --git a/changelog.d/fixes/10734-combo-context-generic-default.md b/changelog.d/fixes/10734-combo-context-generic-default.md new file mode 100644 index 0000000000..988c435d4e --- /dev/null +++ b/changelog.d/fixes/10734-combo-context-generic-default.md @@ -0,0 +1 @@ +- **fix(catalog):** stop counting `getTokenLimit()`'s generic 128k catch-all as a known combo window, so `/v1/models` advertises the min of sourced member contexts instead of collapsing a 500k combo to 128k ([#10734](https://github.com/diegosouzapw/OmniRoute/issues/10734)) diff --git a/changelog.d/fixes/10769-cache-stats-real-cache.md b/changelog.d/fixes/10769-cache-stats-real-cache.md new file mode 100644 index 0000000000..baaacc660d --- /dev/null +++ b/changelog.d/fixes/10769-cache-stats-real-cache.md @@ -0,0 +1 @@ +- **fix(api):** `/api/cache/stats` reported the prompt-cache LRU, which no request path ever writes to — it answered `0 hit / 0 miss, size 0` while the semantic cache served real traffic, and the Health and Usage dashboards rendered that as fact. It now reports the semantic cache's in-memory entries, with the same response shape ([#PRNUM](https://github.com/diegosouzapw/OmniRoute/pull/10769)) — thanks @Poid-ZA, who first fixed this in #9446. diff --git a/changelog.d/fixes/10770-console-interceptor-message-fidelity.md b/changelog.d/fixes/10770-console-interceptor-message-fidelity.md new file mode 100644 index 0000000000..c35260f36a --- /dev/null +++ b/changelog.d/fixes/10770-console-interceptor-message-fidelity.md @@ -0,0 +1 @@ +- **fix(logging):** the app log is filterable and readable again. Entries from the tagged logger (`[LEVEL] [TAG] message`) were filed under the level instead of the component, and printf format strings were never applied, so `%s`/`%d` stayed literal with the values trailing behind them unlabelled — including every LiveWS connection line, where the format is deliberate hardening against injected format specifiers ([#PRNUM](https://github.com/diegosouzapw/OmniRoute/pull/10770)). diff --git a/changelog.d/fixes/10774-claude-code-flat-rate.md b/changelog.d/fixes/10774-claude-code-flat-rate.md new file mode 100644 index 0000000000..ea09e2b208 --- /dev/null +++ b/changelog.d/fixes/10774-claude-code-flat-rate.md @@ -0,0 +1 @@ +- **fix(analytics):** Claude Code (`claude`/`cc`) is a flat-rate subscription, so cost analytics reports `$0` for it instead of estimating Anthropic list prices — the metered `anthropic` API keeps its real cost, and budget/quota/routing still estimate as before ([#10774](https://github.com/diegosouzapw/OmniRoute/pull/10774)) — thanks @electrumguy diff --git a/changelog.d/fixes/10781-wal-truncate-scheduler.md b/changelog.d/fixes/10781-wal-truncate-scheduler.md new file mode 100644 index 0000000000..4eb13a271b --- /dev/null +++ b/changelog.d/fixes/10781-wal-truncate-scheduler.md @@ -0,0 +1 @@ +- fix(db): periodically run `wal_checkpoint(TRUNCATE)` so the SQLite WAL file shrinks on long-running servers (default 6h, override with `OMNIROUTE_WAL_TRUNCATE_INTERVAL_MS`, `0` disables) (#10781) diff --git a/changelog.d/fixes/10782-ws-heartbeat-ping-pong.md b/changelog.d/fixes/10782-ws-heartbeat-ping-pong.md new file mode 100644 index 0000000000..23aeaf3d3a --- /dev/null +++ b/changelog.d/fixes/10782-ws-heartbeat-ping-pong.md @@ -0,0 +1 @@ +- fix(sse): replace LiveWS's application-only liveness check with a protocol-level `ws.ping()`/`pong` heartbeat (RFC 6455 §5.5.2) alongside the existing one, so a read-only dashboard subscriber that never sends anything survives the connection timeout — a socket that stops reading frames entirely is still reaped exactly as before (#10782) diff --git a/changelog.d/fixes/9692-openai-to-claude-tool-images.md b/changelog.d/fixes/9692-openai-to-claude-tool-images.md new file mode 100644 index 0000000000..c082d0dbc3 --- /dev/null +++ b/changelog.d/fixes/9692-openai-to-claude-tool-images.md @@ -0,0 +1 @@ +- **fix(translator):** convert OpenAI `image_url` blocks nested in `role: "tool"` / `tool_result` content to Claude `image` source blocks so OpenAI-compatible clients (Kimi Code CLI `ReadMediaFile`, and any other tool that returns media) no longer 400 the next Claude-format upstream turn ([#9692](https://github.com/diegosouzapw/OmniRoute/issues/9692)) diff --git a/changelog.d/fixes/9708-codex-same-account-retry.md b/changelog.d/fixes/9708-codex-same-account-retry.md new file mode 100644 index 0000000000..2ccb7fb97f --- /dev/null +++ b/changelog.d/fixes/9708-codex-same-account-retry.md @@ -0,0 +1 @@ +- **fix(resilience):** retry a retryable Codex pre-output 502/503/504/507 once on the same account (2–3s jitter) before cooling the connection, and stop translating that mixed pool into an all-accounts quota `429` ([#9708](https://github.com/diegosouzapw/OmniRoute/issues/9708)) diff --git a/changelog.d/fixes/PENDING-electron-window-hidden-hostname-bind.md b/changelog.d/fixes/PENDING-electron-window-hidden-hostname-bind.md new file mode 100644 index 0000000000..6a88ba926a --- /dev/null +++ b/changelog.d/fixes/PENDING-electron-window-hidden-hostname-bind.md @@ -0,0 +1 @@ +- **fix(electron):** desktop window stays hidden on Windows because the embedded Next.js server binds to the machine hostname instead of loopback ([#PENDING](https://github.com/diegosouzapw/OmniRoute/pull/PENDING)) diff --git a/changelog.d/maintenance/10775-remove-dead-enforce-secrets.md b/changelog.d/maintenance/10775-remove-dead-enforce-secrets.md new file mode 100644 index 0000000000..4f44473360 --- /dev/null +++ b/changelog.d/maintenance/10775-remove-dead-enforce-secrets.md @@ -0,0 +1 @@ +- chore(security): remove the unused `enforceSecrets()` duplicate of the boot secret check and pin the live `enforceWebRuntimeEnv()` wiring with a regression test (#10775) diff --git a/changelog.d/maintenance/10779-combo-invocation-docs.md b/changelog.d/maintenance/10779-combo-invocation-docs.md new file mode 100644 index 0000000000..00138a3a65 --- /dev/null +++ b/changelog.d/maintenance/10779-combo-invocation-docs.md @@ -0,0 +1 @@ +- **docs:** Custom combos are only invoked by their exact name in the `model` field — `auto` remains a separate zero-config router, and `openrouter/auto` is a paid OpenRouter product, not an alias ([#10779](https://github.com/diegosouzapw/OmniRoute/pull/10779)) — thanks @maxmad64bis diff --git a/changelog.d/maintenance/release-v3850-basereds-stream-utils-20260820.md b/changelog.d/maintenance/release-v3850-basereds-stream-utils-20260820.md new file mode 100644 index 0000000000..98b62cd448 --- /dev/null +++ b/changelog.d/maintenance/release-v3850-basereds-stream-utils-20260820.md @@ -0,0 +1 @@ +- **fix(tests):** realign the two `stream-utils` passthrough cases that still asserted the pre-#10017 SSE framing — the event-boundary case declares the OpenAI Responses client format it actually exercises, and the metadata case now pins that surviving lines stay inside one event instead of expecting the `:`/`id:` control lines that #10473 stopped forwarding to every client format. diff --git a/config/quality/file-size-baseline.json b/config/quality/file-size-baseline.json index 05323c8002..96001706ef 100644 --- a/config/quality/file-size-baseline.json +++ b/config/quality/file-size-baseline.json @@ -442,12 +442,14 @@ "src/app/(dashboard)/dashboard/providers/[id]/components/modals/AddApiKeyModal.tsx": 1062, "src/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderConnections.ts": 1051, "src/shared/components/ModelSelectModal.tsx": 1138, - "src/shared/constants/providers/apikey/gateways.ts": 1255, + "src/shared/constants/providers/apikey/gateways.ts": 1268, "open-sse/vendor/codex-chatgpt-web/bridge.ts": 1387, "_rebaseline_2026_08_11_v3850_merge_storm_provider_registry": "DRIFT do merge-storm 2026-08-11 (99 PRs mergeados no release/v3.8.50). AddApiKeyModal.tsx (PR #8949 ChatGPT Web provider) e useProviderConnections.ts/ModelSelectModal.tsx (PRs #9011 combo test-all, #9499 image combos) = UI nova legitima acima do cap; gateways.ts = god-file de catalogo de providers que cresceu com PRs #9009/#9421/#9468/#9594 (qualquer split arriscaria corromper o merge de novo — o proprio PR #9421 quebrou o arquivo); bridge.ts (PR #8949) = ponte Chromium vendored; proxyFetch.ts 1207->1220 = drift herdado de merges. Owner autorizou rebaseline com anotacao (2026-08-11).", "src/lib/modelCapabilities.ts": 1006, "src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts": 1014, - "open-sse/config/imageRegistry.ts": 1019 + "open-sse/config/imageRegistry.ts": 1019, + "src/sse/handlers/chatHelpers.ts": 1017, + "src/shared/middleware/chatBodyAdmission.ts": 1005 }, "_rebaseline_base_2026_08_10_proxyfetch": "Base-red fix (green-prs sweep, issue #9985): open-sse/utils/proxyFetch.ts 1207 > cap 1000 — new proxied-TLS fetch helper introduced by the Fal reference-image work. Owner-authorized quick rebaseline to green; structural slim tracked for v3.9.0.", "_rebaseline_2026_07_27_v3849_train2": "Merge-train 2 (7 PRs) — owner-approved 2026-07-27. Single entry: chatCore.ts 4955->5006 (#8595, Responses multi-turn image compaction before the context hard-reject). Genuine irreducible growth at the existing compaction chokepoint in handleChatCore — the PR adds a last-resort retry against the concrete budget plus the estimateFinalInputTokens helper, both wired at the pre-existing call site rather than a new branch. Covered by tests/unit/8560-responses-image-compaction.test.ts (4 tests).", @@ -612,5 +614,6 @@ "_rebaseline_2026_08_12_proxyfetch_redaction": "Base-reds round 3 (#9985): proxyFetch.ts 1220->1239 (+19) = redactProxyDetailsInMessage() helper closing the credential leak #10032 reintroduced (raw proxy URL with user:password appended to the propagated error, Hard Rule #12); irreducible security fix at the existing error-surface chokepoint. Covered by tests/unit/tls-proxy-context.test.ts (strengthened leak guards).", "_rebaseline_2026_08_12_modelcapabilities_snapshot_routing": "Base-reds round 3 (#9985): modelCapabilities.ts crossed the new-file cap at 1006 (+~10) when the context/max-input-token override lookups were routed through the #9199 bulk snapshot (fixing 323 per-model SQLite reads per catalog prepare — auto-combo-context-advertising guard); cohesive change at the existing resolution chokepoints, not extractable. Covered by tests/unit/auto-combo-context-advertising.test.ts + model-capability-resolution-snapshot-9199.test.ts.", "_rebaseline_2026_08_14_imagetotext_servicekinds": "Image-to-Text category (#10275/#10291): gateways.ts grew 1250→1255 by data lines only — the serviceKinds: [\"llm\", \"imageToText\"] declarations on the openrouter and chutes catalog entries, plus the 3-line comment recording why chutes needs no static dots.ocr entry (passthroughModels discovery). No new logic or branching; the file is a provider catalog of declarative metadata. Splitting a catalog for five lines would be worse than the growth (semantic-families rule).", - "_rebaseline_2026_08_18_imageregistry_merge_train": "merge-train 2026-08-18 (owner-authorized, /merge-prs batch of 84): open-sse/config/imageRegistry.ts crossed the 1000-line new-file cap for the first time purely from combining three independent, already-legitimate provider registrations boarded in the same local merge-train — #10542 (aihorde optional-key image catalog), #10494 (gemini-web image generation), #10594 (freepik/magnific provider rename + validation). 996 on release tip -> 1019 on the train tip. Each PR individually adds a small, additive IMAGE_PROVIDERS registry entry at the existing chokepoint; none crosses the cap alone. Not modularized as part of this train's gate fix (out of scope for a merge reconciliation, not a feature change). Covered by each PR's own focused tests (aihorde-image-catalog/generation, gemini-web image tests, freepik/magnific provider tests)." -} + "_rebaseline_2026_08_18_imageregistry_merge_train": "merge-train 2026-08-18 (owner-authorized, /merge-prs batch of 84): open-sse/config/imageRegistry.ts crossed the 1000-line new-file cap for the first time purely from combining three independent, already-legitimate provider registrations boarded in the same local merge-train — #10542 (aihorde optional-key image catalog), #10494 (gemini-web image generation), #10594 (freepik/magnific provider rename + validation). 996 on release tip -> 1019 on the train tip. Each PR individually adds a small, additive IMAGE_PROVIDERS registry entry at the existing chokepoint; none crosses the cap alone. Not modularized as part of this train's gate fix (out of scope for a merge reconciliation, not a feature change). Covered by each PR's own focused tests (aihorde-image-catalog/generation, gemini-web image tests, freepik/magnific provider tests).", + "_rebaseline_2026_08_20_v3850_merge_train_batch1": "Merge-train batch1 (2026-08-19/20, 30 PRs boarded onto release/v3.8.50): gateways.ts 1255->1268 = PR #10722 (Token Kiosk OpenAI-compatible provider gateway catalog entry, +13 declarative lines, same god-file no-split rationale as prior gateways.ts rebaselines); chatHelpers.ts (uncapped, not previously frozen) new 1017 = PR #10797 (relay/bifrost error normalization, +23/-2, own-PR growth, existing file already near cap from accumulated chokepoint wiring per its own rebaseline history above); chatBodyAdmission.ts (uncapped) new 1005 = pre-existing base-red on the pure release tip (1004>1000 before this train boarded anything, no PR in this batch touches this file) — frozen here at its current size, not authorizing further growth. Owner-authorized rebaseline (2026-08-19 merge-prs session)." +} \ No newline at end of file diff --git a/docs/diagrams/cli-terminal.svg b/docs/diagrams/cli-terminal.svg index 99bc29b327..a18765a9c7 100644 --- a/docs/diagrams/cli-terminal.svg +++ b/docs/diagrams/cli-terminal.svg @@ -1,4 +1,4 @@ - + Compact animated terminal cycling three real OmniRoute CLI commands with a typewriter effect and a scrolling subcommand ticker; the first frame shows the completed providers-list screen. diff --git a/docs/diagrams/comparison-table.svg b/docs/diagrams/comparison-table.svg index 80b3cbcdb2..744dbb7d00 100644 --- a/docs/diagrams/comparison-table.svg +++ b/docs/diagrams/comparison-table.svg @@ -1,4 +1,4 @@ - + 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. diff --git a/docs/diagrams/promise-pillars.svg b/docs/diagrams/promise-pillars.svg index a25437f78c..5b692896e9 100644 --- a/docs/diagrams/promise-pillars.svg +++ b/docs/diagrams/promise-pillars.svg @@ -1,4 +1,4 @@ - + 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. @@ -21,7 +21,7 @@ - One endpoint. 341 providers. Never stop building — OmniRoute picks the cheapest one that works. + One endpoint. 342 providers. Never stop building — OmniRoute picks the cheapest one that works. @@ -38,7 +38,7 @@ Never hit limits - Auto-fallback across 341 providers in + Auto-fallback across 342 providers in milliseconds. Quota out? The next provider takes over — zero downtime. diff --git a/docs/diagrams/readme-hero.svg b/docs/diagrams/readme-hero.svg index 0182df44a2..6e13fac6b4 100644 --- a/docs/diagrams/readme-hero.svg +++ b/docs/diagrams/readme-hero.svg @@ -1,4 +1,4 @@ - + Animated hero card: a pulse travels the divider line and a compression bar demo repeatedly shrinks a prompt by up to 95 percent; all headline content is static and readable on the first frame. @@ -28,7 +28,7 @@ Never stop coding. - Every AI tool → 341 providers90+ free — through one endpoint. + Every AI tool → 342 providers90+ free — through one endpoint. Claude Code · Codex · Cursor · Cline · Copilot · Antigravity  →  FREE Claude / GPT / Gemini · auto-fallback diff --git a/docs/getting-started/AUTO-COMBO-GUIDE.md b/docs/getting-started/AUTO-COMBO-GUIDE.md index b5797c780e..fbba5abbe7 100644 --- a/docs/getting-started/AUTO-COMBO-GUIDE.md +++ b/docs/getting-started/AUTO-COMBO-GUIDE.md @@ -189,7 +189,7 @@ Use `auto/smart` when you want the best quality and are okay with occasional exp ### "Can I force a specific provider?" -Yes! Use a combo with `priority` strategy instead of `auto`. See the [Technical Reference](../routing/AUTO-COMBO.md) for details. +Yes! Use a combo with `priority` strategy instead of `auto`, then send the combo's **exact name** as the `model` field (e.g. `model: "my-combo"` — not `auto`). See the [Technical Reference](../routing/AUTO-COMBO.md) for details. ### "How is this different from round-robin?" diff --git a/docs/i18n/ar/llm.txt b/docs/i18n/ar/llm.txt index d5a97ec33a..732d79189c 100644 --- a/docs/i18n/ar/llm.txt +++ b/docs/i18n/ar/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/az/llm.txt b/docs/i18n/az/llm.txt index 6116eb395e..e930a1f05a 100644 --- a/docs/i18n/az/llm.txt +++ b/docs/i18n/az/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/bg/llm.txt b/docs/i18n/bg/llm.txt index 6116eb395e..e930a1f05a 100644 --- a/docs/i18n/bg/llm.txt +++ b/docs/i18n/bg/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/bn/llm.txt b/docs/i18n/bn/llm.txt index 18ab0fc537..baa6656839 100644 --- a/docs/i18n/bn/llm.txt +++ b/docs/i18n/bn/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/cs/llm.txt b/docs/i18n/cs/llm.txt index 08f8297c10..dfb5f9b2b8 100644 --- a/docs/i18n/cs/llm.txt +++ b/docs/i18n/cs/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/da/llm.txt b/docs/i18n/da/llm.txt index 531f324c3a..10ce4811ac 100644 --- a/docs/i18n/da/llm.txt +++ b/docs/i18n/da/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/de/llm.txt b/docs/i18n/de/llm.txt index dfefdf04bf..b5ebeb9c86 100644 --- a/docs/i18n/de/llm.txt +++ b/docs/i18n/de/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/es/llm.txt b/docs/i18n/es/llm.txt index cd36f88e07..72d4fa4a05 100644 --- a/docs/i18n/es/llm.txt +++ b/docs/i18n/es/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/fa/README.md b/docs/i18n/fa/README.md index beab2b5e95..15cb5ef09a 100644 --- a/docs/i18n/fa/README.md +++ b/docs/i18n/fa/README.md @@ -1,14 +1,14 @@ -# 🚀 OmniRoute — The Free AI Gateway (فارسی) +# 🚀 OmniRoute — درگاه رایگان هوش مصنوعی (فارسی) -🌐 **Languages:** 🇺🇸 [English](../../../README.md) · 🇸🇦 [ar](../ar/README.md) · 🇧🇬 [bg](../bg/README.md) · 🇧🇩 [bn](../bn/README.md) · 🇨🇿 [cs](../cs/README.md) · 🇩🇰 [da](../da/README.md) · 🇩🇪 [de](../de/README.md) · 🇪🇸 [es](../es/README.md) · 🇮🇷 [fa](../fa/README.md) · 🇫🇮 [fi](../fi/README.md) · 🇫🇷 [fr](../fr/README.md) · 🇮🇳 [gu](../gu/README.md) · 🇮🇱 [he](../he/README.md) · 🇮🇳 [hi](../hi/README.md) · 🇭🇺 [hu](../hu/README.md) · 🇮🇩 [id](../id/README.md) · 🇮🇹 [it](../it/README.md) · 🇯🇵 [ja](../ja/README.md) · 🇰🇷 [ko](../ko/README.md) · 🇮🇳 [mr](../mr/README.md) · 🇲🇾 [ms](../ms/README.md) · 🇳🇱 [nl](../nl/README.md) · 🇳🇴 [no](../no/README.md) · 🇵🇭 [phi](../phi/README.md) · 🇵🇱 [pl](../pl/README.md) · 🇵🇹 [pt](../pt/README.md) · 🇧🇷 [pt-BR](../pt-BR/README.md) · 🇷🇴 [ro](../ro/README.md) · 🇷🇺 [ru](../ru/README.md) · 🇸🇰 [sk](../sk/README.md) · 🇸🇪 [sv](../sv/README.md) · 🇰🇪 [sw](../sw/README.md) · 🇮🇳 [ta](../ta/README.md) · 🇮🇳 [te](../te/README.md) · 🇹🇭 [th](../th/README.md) · 🇹🇷 [tr](../tr/README.md) · 🇺🇦 [uk-UA](../uk-UA/README.md) · 🇵🇰 [ur](../ur/README.md) · 🇻🇳 [vi](../vi/README.md) · 🇨🇳 [zh-CN](../zh-CN/README.md) +🌐 **زبان‌ها:** 🇺🇸 [English](../../../README.md) · 🇸🇦 [ar](../ar/README.md) · 🇧🇬 [bg](../bg/README.md) · 🇧🇩 [bn](../bn/README.md) · 🇨🇿 [cs](../cs/README.md) · 🇩🇰 [da](../da/README.md) · 🇩🇪 [de](../de/README.md) · 🇪🇸 [es](../es/README.md) · 🇮🇷 [fa](../fa/README.md) · 🇫🇮 [fi](../fi/README.md) · 🇫🇷 [fr](../fr/README.md) · 🇮🇳 [gu](../gu/README.md) · 🇮🇱 [he](../he/README.md) · 🇮🇳 [hi](../hi/README.md) · 🇭🇺 [hu](../hu/README.md) · 🇮🇩 [id](../id/README.md) · 🇮🇹 [it](../it/README.md) · 🇯🇵 [ja](../ja/README.md) · 🇰🇷 [ko](../ko/README.md) · 🇮🇳 [mr](../mr/README.md) · 🇲🇾 [ms](../ms/README.md) · 🇳🇱 [nl](../nl/README.md) · 🇳🇴 [no](../no/README.md) · 🇵🇭 [phi](../phi/README.md) · 🇵🇱 [pl](../pl/README.md) · 🇵🇹 [pt](../pt/README.md) · 🇧🇷 [pt-BR](../pt-BR/README.md) · 🇷🇴 [ro](../ro/README.md) · 🇷🇺 [ru](../ru/README.md) · 🇸🇰 [sk](../sk/README.md) · 🇸🇪 [sv](../sv/README.md) · 🇰🇪 [sw](../sw/README.md) · 🇮🇳 [ta](../ta/README.md) · 🇮🇳 [te](../te/README.md) · 🇹🇭 [th](../th/README.md) · 🇹🇷 [tr](../tr/README.md) · 🇺🇦 [uk-UA](../uk-UA/README.md) · 🇵🇰 [ur](../ur/README.md) · 🇻🇳 [vi](../vi/README.md) · 🇨🇳 [zh-CN](../zh-CN/README.md) --- -### Keep coding through provider limits. Smart routing to free-access and low-cost AI models with automatic fallback. +### کدنویسی را از طریق محدودیت های ارائه دهنده ادامه دهید. مسیریابی هوشمند به مدل‌های هوش مصنوعی با دسترسی رایگان و کم‌هزینه با بازگشت خودکار. -_Your universal API proxy — one endpoint, 329 provider catalog entries, resilient fallback subject to upstream availability. Includes **MCP Server (107 tools, 32 scopes)**, **A2A Protocol**, **Memory/Skills Systems** & **Electron Desktop App**._ +_پراکسی جهانی API شما - یک نقطه پایانی، 329 ورودی کاتالوگ ارائه‌دهنده، بازگشت انعطاف‌پذیر به شرط در دسترس بودن بالادست. شامل **سرور MCP (107 ابزار، 32 دامنه)**، **پروتکل A2A**، **سیستم های حافظه/مهارت** و **برنامه دسکتاپ الکترونیک**._ -**Chat Completions • Embeddings • Image Generation • Video • Music • Audio • Reranking • **Web Search** • MCP Server • A2A Protocol • 100% TypeScript** +** تکمیل چت • جاسازی ها • تولید تصویر • ویدئو • موسیقی • صدا • رتبه بندی مجدد • **جستجوی وب** • سرور MCP • پروتکل A2A • 100% TypeScript** --- @@ -17,12 +17,12 @@ _Your universal API proxy — one endpoint, 329 provider catalog entries, resili [![npm version](https://img.shields.io/npm/v/omniroute?color=cb3837&logo=npm)](https://www.npmjs.com/package/omniroute) [![Docker Hub](https://img.shields.io/docker/v/diegosouzapw/omniroute?label=Docker%20Hub&logo=docker&color=2496ED)](https://hub.docker.com/r/diegosouzapw/omniroute) -![NPM Downloads](https://img.shields.io/npm/dw/omniroute?label=npm%20down%20week&color=red) -![NPM Downloads](https://img.shields.io/npm/dm/omniroute?label=npm%20down%20month&color=red) +![بارگیری‌های NPM](https://img.shields.io/npm/dw/omniroute?label=npm%20down%20week&color=red) +![بارگیری‌های NPM](https://img.shields.io/npm/dm/omniroute?label=npm%20down%20month&color=red) -![NPM Downloads](https://img.shields.io/npm/d18m/omniroute?label=npm%20down%20year&color=red) +![بارگیری‌های NPM](https://img.shields.io/npm/d18m/omniroute?label=npm%20down%20year&color=red) ![Docker Pulls](https://img.shields.io/docker/pulls/diegosouzapw/omniroute) -![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/diegosouzapw/omniroute/total?style=flat&label=eletron%20donwloads&color=blue) +![بارگیری‌های GitHub (همه دارایی‌ها، همه نسخه‌ها)](https://img.shields.io/github/downloads/diegosouzapw/omniroute/total?style=flat&label=eletron%20donwloads&color=blue) [![stars](https://custom-icon-badges.demolab.com/github/stars/diegosouzapw/OmniRoute?logo=star&style=flat)](https://github.com/diegosouzapw/OmniRoute/stargazers) [![open issues](https://custom-icon-badges.demolab.com/github/issues-raw/diegosouzapw/OmniRoute?logo=issue)](https://github.com/diegosouzapw/OmniRoute/issues) @@ -45,11 +45,11 @@ _Your universal API proxy — one endpoint, 329 provider catalog entries, resili
-🌐 **Available in:** 🇺🇸 [English](README.md) | 🇧🇷 [Português (Brasil)](docs/i18n/pt-BR/README.md) | 🇪🇸 [Español](docs/i18n/es/README.md) | 🇫🇷 [Français](docs/i18n/fr/README.md) | 🇮🇹 [Italiano](docs/i18n/it/README.md) | 🇷🇺 [Русский](docs/i18n/ru/README.md) | 🇨🇳 [中文 (简体)](docs/i18n/zh-CN/README.md) | 🇩🇪 [Deutsch](docs/i18n/de/README.md) | 🇮🇳 [हिन्दी](docs/i18n/in/README.md) | 🇹🇭 [ไทย](docs/i18n/th/README.md) | 🇺🇦 [Українська](docs/i18n/uk-UA/README.md) | 🇸🇦 [العربية](docs/i18n/ar/README.md) | 🇯🇵 [日本語](docs/i18n/ja/README.md) | 🇻🇳 [Tiếng Việt](docs/i18n/vi/README.md) | 🇧🇬 [Български](docs/i18n/bg/README.md) | 🇩🇰 [Dansk](docs/i18n/da/README.md) | 🇫🇮 [Suomi](docs/i18n/fi/README.md) | 🇮🇱 [עברית](docs/i18n/he/README.md) | 🇭🇺 [Magyar](docs/i18n/hu/README.md) | 🇮🇩 [Bahasa Indonesia](docs/i18n/id/README.md) | 🇰🇷 [한국어](docs/i18n/ko/README.md) | 🇲🇾 [Bahasa Melayu](docs/i18n/ms/README.md) | 🇳🇱 [Nederlands](docs/i18n/nl/README.md) | 🇳🇴 [Norsk](docs/i18n/no/README.md) | 🇵🇹 [Português (Portugal)](docs/i18n/pt/README.md) | 🇷🇴 [Română](docs/i18n/ro/README.md) | 🇵🇱 [Polski](docs/i18n/pl/README.md) | 🇸🇰 [Slovenčina](docs/i18n/sk/README.md) | 🇸🇪 [Svenska](docs/i18n/sv/README.md) | 🇵🇭 [Filipino](docs/i18n/phi/README.md) | 🇨🇿 [Čeština](docs/i18n/cs/README.md) +🌐 **موجود در:** 🇺🇸 [انگلیسی](README.md) | 🇧🇷 [پرتغال (برزیل)](docs/i18n/pt-BR/README.md) | 🇪🇸 [اسپانیول](docs/i18n/es/README.md) | 🇫🇷 [Français](docs/i18n/fr/README.md) | 🇮🇹 [ایتالیانو](docs/i18n/it/README.md) | 🇷🇺 [Русский](docs/i18n/ru/README.md) | 🇨🇳 [中文 (简体)](docs/i18n/zh-CN/README.md) | 🇩🇪 [دویچ](docs/i18n/de/README.md) | 🇮🇳 [हिन्दी](docs/i18n/in/README.md) | 🇹🇭 [ไทย](docs/i18n/th/README.md) | 🇺🇦 [Українська](docs/i18n/uk-UA/README.md) | 🇸🇦 [العربیة](docs/i18n/ar/README.md) | 🇯🇵 [日本語](docs/i18n/ja/README.md) | 🇻🇳 [Tiếng Việt](docs/i18n/vi/README.md) | 🇧🇬 [Български](docs/i18n/bg/README.md) | 🇩🇰 [دانسک](docs/i18n/da/README.md) | 🇫🇮 [Suomi](docs/i18n/fi/README.md) | 🇮🇱 [עברית](docs/i18n/he/README.md) | 🇭🇺 [مگیار](docs/i18n/hu/README.md) | 🇮🇩 [Bahasa Indonesia](docs/i18n/id/README.md) | 🇰🇷 [한국어](docs/i18n/ko/README.md) | 🇲🇾 [Bahasa Melayu](docs/i18n/ms/README.md) | 🇳🇱 [هلند](docs/i18n/nl/README.md) | 🇳🇴 [نورسک](docs/i18n/no/README.md) | 🇵🇹 [پرتغال (پرتغال)](docs/i18n/pt/README.md) | 🇷🇴 [Română](docs/i18n/ro/README.md) | 🇵🇱 [Polski](docs/i18n/pl/README.md) | 🇸🇰 [Slovenčina](docs/i18n/sk/README.md) | 🇸🇪 [Svenska](docs/i18n/sv/README.md) | 🇵🇭 [فیلیپینی](docs/i18n/phi/README.md) | 🇨🇿 [Čeština](docs/i18n/cs/README.md) --- -## 🖼️ Main Dashboard +## 🖼️ داشبورد اصلی
OmniRoute Dashboard @@ -57,30 +57,30 @@ _Your universal API proxy — one endpoint, 329 provider catalog entries, resili --- -## 📸 Dashboard Preview +## 📸 پیش نمایش داشبورد
Click to see dashboard screenshots -| Page | Screenshot | +| صفحه | اسکرین شات | | -------------- | ------------------------------------------------- | -| **Providers** | ![Providers](docs/screenshots/01-providers.png) | -| **Combos** | ![Combos](docs/screenshots/02-combos.png) | -| **Analytics** | ![Analytics](docs/screenshots/03-analytics.png) | -| **Health** | ![Health](docs/screenshots/04-health.png) | -| **Translator** | ![Translator](docs/screenshots/05-translator.png) | -| **Settings** | ![Settings](docs/screenshots/06-settings.png) | -| **CLI Tools** | ![CLI Tools](docs/screenshots/07-cli-tools.png) | -| **Usage Logs** | ![Usage](docs/screenshots/08-usage.png) | -| **Endpoints** | ![Endpoints](docs/screenshots/09-endpoint.png) | +| **ارائه دهندگان** | ![ارائه دهندگان](docs/screenshots/01-providers.png) | +| **ترکیب** | ![Combos](docs/screenshots/02-combos.png) | +| **تحلیل** | ![Analytics](docs/screenshots/03-analytics.png) | +| **سلامت** | ![سلامت](docs/screenshots/04-health.png) | +| **مترجم** | ![مترجم](docs/screenshots/05-translator.png) | +| **تنظیمات** | ![تنظیمات](docs/screenshots/06-settings.png) | +| **ابزار CLI** | ![ابزار CLI](docs/screenshots/07-cli-tools.png) | +| ** سیاهههای استفاده ** | ![استفاده](docs/screenshots/08-usage.png) | +| **نقاط پایانی** | ![نقاط پایانی](docs/screenshots/09-endpoint.png) |
--- -### 🤖 Free AI Provider for your favorite coding agents +### 🤖 ارائه دهنده رایگان هوش مصنوعی برای عوامل برنامه نویسی مورد علاقه شما -_Connect any AI-powered IDE or CLI tool through OmniRoute — free-access AI gateway; provider limits and terms apply._ +_هر ابزار IDE یا CLI مجهز به هوش مصنوعی را از طریق OmniRoute - دروازه هوش مصنوعی با دسترسی آزاد وصل کنید. محدودیت ها و شرایط ارائه دهنده اعمال می شود._ @@ -138,14 +138,14 @@ _Connect any AI-powered IDE or CLI tool through OmniRoute — free-access AI gat @@ -156,46 +156,46 @@ _Connect any AI-powered IDE or CLI tool through OmniRoute — free-access AI gat --- -## 🤔 Why OmniRoute? +## 🤔 چرا OmniRoute؟ -**Stop wasting money and hitting limits:** +**از هدر دادن پول و رسیدن به محدودیت ها جلوگیری کنید:** -- Subscription quota expires unused every month -- Rate limits stop you mid-coding -- Expensive APIs ($20-50/month per provider) -- Manual switching between providers +- سهمیه اشتراک بدون استفاده هر ماه منقضی می شود +- محدودیت های نرخ شما را در میانه کدنویسی متوقف می کند +- API های گران قیمت (20-50 دلار در ماه برای هر ارائه دهنده) +- تعویض دستی بین ارائه دهندگان -**OmniRoute solves this:** +**OmniRoute این مشکل را حل می کند:** -- ✅ **Maximize subscriptions** - Track quota, use every bit before reset -- ✅ **Auto fallback** - Subscription → API Key → Cheap → Free; availability depends on eligible upstream routes -- ✅ **Multi-account** - Round-robin between accounts per provider +- ✅ ** اشتراک ها را به حداکثر برسانید ** - سهمیه را پیگیری کنید، از هر بیت قبل از تنظیم مجدد استفاده کنید +- ✅ ** بازگشت خودکار ** - اشتراک → کلید API → ارزان → رایگان. در دسترس بودن بستگی به مسیرهای واجد شرایط بالادست دارد +- ✅ **چند حساب ** - دور برگشت بین حساب ها در هر ارائه دهنده --- -## 📧 Support +## 📧 پشتیبانی -> 💬 **Join our community!** [WhatsApp Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) — Get help, share tips, and stay updated. +> 💬 **به انجمن ما بپیوندید!** [گروه واتساپ](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) - راهنمایی دریافت کنید، نکات را به اشتراک بگذارید و به روز بمانید. -- **Website**: [omniroute.online](https://omniroute.online) +- **وب سایت**: [omniroute.online](https://omniroute.online) - **GitHub**: [github.com/diegosouzapw/OmniRoute](https://github.com/diegosouzapw/OmniRoute) -- **Issues**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues) -- **WhatsApp**: [Community Group](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) -- **Contributing**: See [CONTRIBUTING.md](CONTRIBUTING.md), open a PR, or pick a `good first issue` +- **مشکلات**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues) +- **WhatsApp**: [گروه انجمن](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t) +- **مشارکت**: به [CONTRIBUTING.md](CONTRIBUTING.md) مراجعه کنید، یک PR باز کنید، یا یک `good first issue` انتخاب کنید -### 🐛 Reporting a Bug? +### 🐛 یک اشکال را گزارش می کنید؟ -When opening an issue, please run the system-info command and attach the generated file: +هنگام باز کردن یک مشکل، لطفاً دستور system-info را اجرا کنید و فایل تولید شده را پیوست کنید: ```bash npm run system-info ``` -This generates a `system-info.txt` with your Node.js version, OmniRoute version, OS details, installed CLI tools (qoder, gemini, claude, codex, antigravity, droid, etc.), Docker/PM2 status, and system packages — everything we need to reproduce your issue quickly. Attach the file directly to your GitHub issue. +این فرمان فایل `system-info.txt` را شامل نسخه Node.js و OmniRoute، جزئیات سیستم‌عامل، ابزارهای CLI نصب‌شده (qoder، gemini، claude، codex، antigravity، droid و غیره)، وضعیت Docker/PM2 و بسته‌های سیستم تولید می‌کند؛ هرآنچه برای بازتولید سریع مشکل لازم است. فایل را مستقیماً به گزارش مشکل GitHub پیوست کنید. --- -## 🔄 How It Works +## 🔄 چگونه کار می کند ``` ┌─────────────┐ @@ -224,467 +224,467 @@ Result: broader fallback coverage and cost control; availability is not guarante --- -## 🎯 What OmniRoute Solves — 30 Real Pain Points & Use Cases +## 🎯 آنچه OmniRoute حل می کند - 30 نقطه درد واقعی و موارد استفاده -> **Every developer using AI tools faces these problems daily.** OmniRoute was built to solve them all — from cost overruns to regional blocks, from broken OAuth flows to protocol operations and enterprise observability. +> **هر برنامه‌نویسی که از ابزارهای هوش مصنوعی استفاده می‌کند، روزانه با این مشکلات روبرو می‌شود. ** OmniRoute برای حل همه آنها ساخته شده است - از مازاد هزینه تا بلوک‌های منطقه‌ای، از جریان‌های شکسته OAuth تا عملیات پروتکل و قابلیت مشاهده سازمانی.
-💸 1. "I pay for an expensive subscription but still get interrupted by limits" +💸 ۱. «برای اشتراک گران‌قیمت پول می‌دهم، اما محدودیت‌ها همچنان کارم را قطع می‌کنند» -Developers pay $20–200/month for Claude Pro, Codex Pro, or GitHub Copilot. Even paying, quota has a ceiling — 5h of usage, weekly limits, or per-minute rate limits. Mid-coding session, the provider stops responding and the developer loses flow and productivity. +توسعه‌دهندگان 20 تا 200 دلار در ماه برای Claude Pro، Codex Pro، یا GitHub Copilot می‌پردازند. حتی با پرداخت، سهمیه سقفی دارد - 5 ساعت استفاده، محدودیت های هفتگی یا محدودیت نرخ در دقیقه. در اواسط جلسه کدنویسی، ارائه دهنده پاسخ نمی دهد و توسعه دهنده جریان و بهره وری را از دست می دهد. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **Smart 4-Tier Fallback** — If subscription quota runs out, automatically redirects to API Key → Cheap → Free with zero manual intervention -- **Provider Limits Tracking** — Cached quota snapshots refresh on a server-side schedule (default `PROVIDER_LIMITS_SYNC_INTERVAL_MINUTES=70`) with manual refresh available in the UI -- **Multi-Account Support** — Multiple accounts per provider with auto round-robin — when one runs out, switches to the next -- **Custom Combos** — Customizable fallback chains with 13 balancing strategies (priority, weighted, fill-first, round-robin, P2C, random, least-used, cost-optimized, strict-random, auto, lkgp, context-optimized, **context-relay**) -- **Structured Combo Builder** — Build combos step-by-step with explicit provider + model + account selection, including repeated providers and fixed-account targets -- **Quota-Aware P2C** — Power-of-two account selection now factors quota headroom, backoff, recent errors, and consecutive use -- **Codex Business Quotas** — Business/Team workspace quota monitoring directly in the dashboard +- ** بازگشت هوشمند 4-سطحی ** - اگر سهمیه اشتراک تمام شود، به طور خودکار به کلید API هدایت می شود → ارزان → رایگان با دخالت دستی صفر +- **ردیابی محدودیت های ارائه دهنده** - عکس های لحظه ای سهمیه ذخیره شده در حافظه پنهان در یک برنامه زمانی سمت سرور (پیش فرض `PROVIDER_LIMITS_SYNC_INTERVAL_MINUTES=70`) با بازخوانی دستی موجود در رابط کاربری بازخوانی می شوند. +- **پشتیبانی چند حساب** - چندین حساب در هر ارائه دهنده با چرخش خودکار - وقتی یکی تمام شد، به حساب بعدی تغییر می کند +- **ترکیب های سفارشی** - زنجیره های بازگشتی قابل تنظیم با 13 استراتژی متعادل کننده (اولویت، وزن، پر کردن، دور روبین، P2C، تصادفی، کم استفاده، بهینه سازی هزینه، تصادفی دقیق، خودکار، lkgp، بهینه سازی زمینه، **رله زمینه**) +- **سازگار ترکیبی ساختاریافته** - ساخت ترکیبی گام به گام با ارائه دهنده صریح + مدل + انتخاب حساب، از جمله ارائه دهندگان مکرر و اهداف حساب ثابت +- **Quota-Aware P2C** - انتخاب اکانت قدرت از دو در حال حاضر سهمیه حجم، عقب نشینی، خطاهای اخیر و استفاده متوالی را فاکتور می کند. +- ** Codex سهمیه های تجاری ** - نظارت بر سهمیه فضای کاری تجاری/تیم به طور مستقیم در داشبورد
-🔌 2. "I need to use multiple providers but each has a different API" +🔌 ۲. «به چند ارائه‌دهنده نیاز دارم، اما هرکدام API متفاوتی دارند» -OpenAI uses one format, Claude (Anthropic) uses another, Gemini yet another. If a dev wants to test models from different providers or fallback between them, they need to reconfigure SDKs, change endpoints, deal with incompatible formats. Custom providers (FriendLI, NIM) have non-standard model endpoints. +OpenAI از یک قالب استفاده می کند، Claude (انتروپیک) از فرمت دیگری، جمینی از فرمت دیگری استفاده می کند. اگر یک برنامه‌نویس بخواهد مدل‌هایی را از ارائه‌دهندگان مختلف آزمایش کند یا بین آن‌ها بازگشتی ایجاد کند، باید SDK‌ها را دوباره پیکربندی کند، نقاط پایانی را تغییر دهد، با فرمت‌های ناسازگار برخورد کند. ارائه دهندگان سفارشی (FriendLI، NIM) دارای نقاط پایانی مدل غیر استاندارد هستند. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **Unified Endpoint** — A single `http://localhost:20128/v1` serves as proxy for all 329 provider catalog entries -- **Format Translation** — Automatic and transparent: OpenAI ↔ Claude ↔ Gemini ↔ Responses API -- **Response Sanitization** — Strips non-standard fields (`x_groq`, `usage_breakdown`, `service_tier`) that break OpenAI SDK v1.83+ -- **Role Normalization** — Converts `developer` → `system` for non-OpenAI providers; `system` → `user` for GLM/ERNIE -- **Think Tag Extraction** — Extracts `` blocks from models like DeepSeek R1 into standardized `reasoning_content` -- **Structured Output for Gemini** — `json_schema` → `responseMimeType`/`responseSchema` automatic conversion -- **`stream` defaults to `false`** — Aligns with OpenAI spec, avoiding unexpected SSE in Python/Rust/Go SDKs +- **نقطه پایانی یکپارچه** - یک `http://localhost:20128/v1` به عنوان پروکسی برای تمام 329 ورودی کاتالوگ ارائه دهنده عمل می کند +- **ترجمه فرمت** — خودکار و شفاف: OpenAI ↔ Claude ↔ Gemini ↔ پاسخ ها API +- **عفونی‌سازی پاسخ** - فیلدهای غیر استاندارد (`x_groq`، `usage_breakdown`، `service_tier`) را که OpenAI SDK v1.83+ را می‌شکنند، حذف می‌کند. +- ** عادی سازی نقش ** - تبدیل `developer` → `system` برای ارائه دهندگان غیر OpenAI. `system` → `user` برای GLM/ERNIE +- **Think Tag Extraction** - بلوک های `` را از مدل هایی مانند DeepSeek R1 به استاندارد `reasoning_content` استخراج می کند +- **خروجی ساختاریافته برای Gemini** — تبدیل خودکار `json_schema` → `responseMimeType`/`responseSchema` +- **`stream` به طور پیش فرض روی `false`** تنظیم می شود - با مشخصات OpenAI همسو می شود، از SSE غیرمنتظره در SDK های Python/Rust/Go اجتناب می کند
-🌐 3. "My AI provider blocks my region/country" +🌐 ۳. «ارائه‌دهندهٔ هوش مصنوعی، منطقه یا کشور من را مسدود می‌کند» -Providers like OpenAI/Codex block access from certain geographic regions. Users get errors like `unsupported_country_region_territory` during OAuth and API connections. This is especially frustrating for developers from developing countries. +ارائه دهندگانی مانند OpenAI/Codex دسترسی از مناطق جغرافیایی خاص را مسدود می کنند. کاربران در طول اتصالات OAuth و API خطاهایی مانند `unsupported_country_region_territory` دریافت می کنند. این امر به ویژه برای توسعه دهندگان کشورهای در حال توسعه ناامید کننده است. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **3-Level Proxy Config** — Configurable proxy at 3 levels: global (all traffic), per-provider (one provider only), and per-connection/key -- **Color-Coded Proxy Badges** — Visual indicators: 🟢 global proxy, 🟡 provider proxy, 🔵 connection proxy, always showing the IP -- **OAuth Token Exchange Through Proxy** — OAuth flow also goes through the proxy, solving `unsupported_country_region_territory` -- **Connection Tests via Proxy** — Connection tests use the configured proxy (no more direct bypass) -- **SOCKS5 Support** — Full SOCKS5 proxy support for outbound routing -- **TLS Fingerprint Spoofing** — Browser-like TLS fingerprint via `wreq-js` to bypass bot detection -- **🔏 CLI Fingerprint Matching** — Reorders headers and body fields to match native CLI binary signatures, drastically reducing account flagging risk. The proxy IP is preserved — you get both stealth **and** IP masking simultaneously +- ** پیکربندی پروکسی 3 سطح ** - پروکسی قابل تنظیم در 3 سطح: جهانی (تمام ترافیک)، هر ارائه دهنده (فقط یک ارائه دهنده) و هر اتصال/کلید +- **نشانهای پروکسی با کد رنگی** - نشانگرهای تصویری: پروکسی جهانی، پروکسی ارائه دهنده، 🔵 پروکسی اتصال، همیشه IP را نشان می دهد +- ** تبادل رمز OAuth از طریق پروکسی** — جریان OAuth نیز از طریق پروکسی می رود و `unsupported_country_region_territory` را حل می کند +- **تست های اتصال از طریق پروکسی** - تست های اتصال از پروکسی پیکربندی شده استفاده می کنند (دیگر دور زدن مستقیم وجود ندارد) +- **پشتیبانی SOCKS5** - پشتیبانی کامل از پروکسی SOCKS5 برای مسیریابی خروجی +- **تقلب اثر انگشت TLS** - اثر انگشت TLS مرورگر مانند از طریق `wreq-js` برای دور زدن تشخیص ربات +- ** IP پروکسی حفظ می شود - شما هر دو پنهان **و** IP را به طور همزمان دریافت می کنید
-🆓 4. "I want to use AI for coding but I have no money" +🆓 ۴. «می‌خواهم برای برنامه‌نویسی از هوش مصنوعی استفاده کنم، اما بودجه‌ای ندارم» -Not everyone can pay $20–200/month for AI subscriptions. Students, devs from emerging countries, hobbyists, and freelancers need access to quality models at zero cost. +همه نمی توانند 20 تا 200 دلار در ماه برای اشتراک هوش مصنوعی بپردازند. دانش‌آموزان، توسعه‌دهندگان کشورهای نوظهور، علاقه‌مندان و مشاغل آزاد نیاز به دسترسی به مدل‌های باکیفیت با هزینه صفر دارند. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **Ollama Cloud** — Cloud-hosted Ollama models at `api.ollama.com` with free "Light usage" tier; use `ollamacloud/` prefix -- **Free-Only Combos** — Chain `if/kimi-k2-thinking → qw/qwen3-coder-plus` can use currently listed $0 access; limits and availability apply -- **NVIDIA NIM Free Access** — ~40 RPM free access as currently listed; provider terms and model availability apply at build.nvidia.com (transitioning from credits to pure rate limits) -- **Cost Optimized Strategy** — Routing strategy that automatically chooses the cheapest available provider +- **Ollama Cloud** - مدل های Ollama میزبان ابر در `api.ollama.com` با سطح رایگان "استفاده از نور". از پیشوند `ollamacloud/` استفاده کنید +- **ترکیب‌های فقط رایگان** - زنجیره `if/kimi-k2-thinking → qw/qwen3-coder-plus` می‌تواند از دسترسی $0 فهرست‌شده فعلی استفاده کند. محدودیت ها و در دسترس بودن اعمال می شود +- **NVIDIA NIM دسترسی رایگان ** — دسترسی آزاد ~40 RPM همانطور که در حال حاضر لیست شده است. شرایط ارائه دهنده و در دسترس بودن مدل در build.nvidia.com اعمال می شود (انتقال از اعتبار به محدودیت نرخ خالص) +- **استراتژی بهینه سازی هزینه** - استراتژی مسیریابی که به طور خودکار ارزان ترین ارائه دهنده موجود را انتخاب می کند
-🔒 5. "I need to protect my AI gateway from unauthorized access" +🔒 ۵. «باید درگاه هوش مصنوعی‌ام را در برابر دسترسی غیرمجاز محافظت کنم» -When exposing an AI gateway to the network (LAN, VPS, Docker), anyone with the address can consume the developer's tokens/quota. Without protection, APIs are vulnerable to misuse, prompt injection, and abuse. +هنگامی که یک دروازه هوش مصنوعی را در معرض شبکه قرار می دهید (LAN، VPS، Docker)، هر کسی که آدرس را داشته باشد می تواند توکن ها/سهمیه توسعه دهنده را مصرف کند. بدون محافظت، APIها در برابر سوء استفاده، تزریق سریع و سوء استفاده آسیب پذیر هستند. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **API Key Management** — Generation, rotation, and scoping per provider with a dedicated `/dashboard/api-manager` page -- **Model-Level Permissions** — Restrict API keys to specific models (`openai/*`, wildcard patterns), with Allow All/Restrict toggle -- **API Endpoint Protection** — Require a key for `/v1/models` and block specific providers from the listing -- **Auth Guard + CSRF Protection** — All dashboard routes protected with `withAuth` middleware + CSRF tokens -- **Rate Limiter** — Per-IP rate limiting with configurable windows -- **IP Filtering** — Allowlist/blocklist for access control -- **Prompt Injection Guard** — Sanitization against malicious prompt patterns -- **AES-256-GCM Encryption** — Credentials encrypted at rest +- **API مدیریت کلید** — تولید، چرخش و محدوده برای هر ارائه دهنده با صفحه اختصاصی `/dashboard/api-manager` +- **مجوزهای سطح مدل** - کلیدهای API را به مدل‌های خاص محدود کنید (`openai/*`، الگوهای عام)، با تغییر حالت Allow All/Restrict +- **API حفاظت نقطه پایانی** - نیاز به کلید برای `/v1/models` و مسدود کردن ارائه دهندگان خاص از فهرست +- **Auth Guard + CSRF Protection** - همه مسیرهای داشبورد با میان افزار `withAuth` + توکن های CSRF محافظت می شوند +- **Rate Limiter** - محدود کردن نرخ به ازای IP با پنجره های قابل تنظیم +- ** فیلتر IP ** - لیست مجاز / لیست مسدود برای کنترل دسترسی +- **محافظ تزریق سریع** - ضدعفونی کردن در برابر الگوهای سریع مخرب +- ** رمزگذاری AES-256-GCM ** - اعتبارنامه ها در حالت استراحت رمزگذاری شده اند
-🛑 6. "My provider went down and I lost my coding flow" +🛑 ۶. «ارائه‌دهنده از دسترس خارج شد و جریان برنامه‌نویسی‌ام را از دست دادم» -AI providers can become unstable, return 5xx errors, or hit temporary rate limits. If a dev depends on a single provider, they're interrupted. Without circuit breakers, repeated retries can crash the application. +ارائه‌دهندگان هوش مصنوعی می‌توانند ناپایدار شوند، خطاهای 5xx را برگردانند یا به محدودیت‌های نرخ موقت برسند. اگر یک توسعه دهنده به یک ارائه دهنده وابسته باشد، آنها قطع می شوند. بدون قطع کننده مدار، تلاش های مجدد مکرر می تواند برنامه را خراب کند. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **Request Queue & Pacing** — Per-connection request buckets smooth bursts before they hit upstream rate caps -- **Connection Cooldown** — A single connection cools down after retryable failures with optional upstream `Retry-After` hints and exponential backoff -- **Provider Circuit Breaker** — The provider only trips after fallback is exhausted and the provider request still fails with provider-wide transient errors; connection-scoped `429` rate limits stay in Connection Cooldown -- **Wait For Cooldown** — The server can wait for the earliest connection cooldown to expire and retry the same client request automatically -- **Anti-Thundering Herd** — Mutex + semaphore protection against concurrent retry storms -- **Combo Fallback Chains** — If the primary provider fails, automatically falls through the chain with no intervention -- **Health Dashboard** — Uptime monitoring, provider circuit breaker states, cooldowns, cache stats, p50/p95/p99 latency +- **صف و سرعت درخواست** - سطل های درخواست هر اتصال قبل از اینکه به سقف های نرخ بالادستی برسند، یکنواخت می شوند +- ** خنک کننده اتصال ** - یک اتصال واحد پس از خرابی های قابل امتحان مجدد با نکات اختیاری بالادست `Retry-After` و عقب نشینی نمایی خنک می شود +- ** مدار شکن ارائه دهنده** - ارائه دهنده فقط پس از اتمام بازگشت مجدد و درخواست ارائه دهنده با خطاهای گذرا در سراسر ارائه دهنده با شکست مواجه می شود. محدودیت‌های سرعت `429` با محدوده اتصال، در Cooldown اتصال باقی می‌مانند +- **Wait For Cooldown** - سرور می تواند منتظر بماند تا اولین خنک شدن اتصال منقضی شود و دوباره همان درخواست مشتری را به طور خودکار امتحان کند. +- ** گله ضد رعد ** - محافظت موتکس + سمافور در برابر طوفان های تکراری همزمان +- ** زنجیره های بازگشتی ترکیبی ** - اگر ارائه دهنده اصلی شکست بخورد، به طور خودکار بدون مداخله از طریق زنجیره می افتد +- ** داشبورد سلامت ** - نظارت بر زمان، وضعیت های قطع کننده مدار ارائه دهنده، خنک شدن، آمار حافظه پنهان، تاخیر p50/p95/p99
-🔧 7. "Configuring each AI tool is tedious and repetitive" +🔧 ۷. «پیکربندی تک‌تک ابزارهای هوش مصنوعی خسته‌کننده و تکراری است» -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **CLI Tools Dashboard** — Dedicated page with one-click setup for Claude Code, Codex CLI, OpenClaw, Kilo Code, Antigravity, Cline -- **GitHub Copilot Config Generator** — Generates `chatLanguageModels.json` for VS Code with bulk model selection -- **Onboarding Wizard** — Guided 4-step setup for first-time users -- **One endpoint, all models** — Configure `http://localhost:20128/v1` once, access 329 provider catalog entries +- **داشبورد ابزارهای CLI** — صفحه‌ای اختصاصی با راه‌اندازی تک‌کلیکی برای Claude Code، Codex CLI، OpenClaw، Kilo Code، Antigravity و Cline +- **GitHub Copilot Config Generator** — `chatLanguageModels.json` را برای کد VS با انتخاب مدل انبوه تولید می کند +- **جادوگر سوار شدن** - راه اندازی 4 مرحله ای هدایت شده برای کاربرانی که اولین بار هستند +- **یک نقطه پایانی، همه مدل ها** - یک بار `http://localhost:20128/v1` را پیکربندی کنید، به 329 ورودی کاتالوگ ارائه دهنده دسترسی داشته باشید
-🔑 8. "Managing OAuth tokens from multiple providers is hell" +🔑 ۸. «مدیریت توکن‌های OAuth چندین ارائه‌دهنده بسیار دشوار است» -Claude Code, Codex, Copilot — all use OAuth 2.0 with expiring tokens. Developers need to re-authenticate constantly, deal with `client_secret is missing`, `redirect_uri_mismatch`, and failures on remote servers. OAuth on LAN/VPS is particularly problematic. +کد Claude، Codex، Copilot — همه از OAuth 2.0 با توکن های در حال انقضا استفاده می کنند. توسعه‌دهندگان باید دائماً احراز هویت مجدد کنند، با `client_secret is missing`، `redirect_uri_mismatch` و خرابی‌های سرورهای راه دور مقابله کنند. OAuth در LAN/VPS به ویژه مشکل ساز است. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **Auto Token Refresh** — OAuth tokens refresh in background before expiration -- **OAuth 2.0 (PKCE) Built-in** — Automatic flow for Claude Code, Codex, Copilot, Kiro, Qwen, Qoder -- **Multi-Account OAuth** — Multiple accounts per provider via JWT/ID token extraction -- **OAuth LAN/Remote Fix** — Private IP detection for `redirect_uri` + manual URL mode for remote servers -- **OAuth Behind Nginx** — Uses `window.location.origin` for reverse proxy compatibility -- **Remote OAuth Guide** — Step-by-step guide for Google Cloud credentials on VPS/Docker +- **بازسازی خودکار توکن** - توکن های OAuth قبل از انقضا در پس زمینه به روز می شوند +- **OAuth 2.0 (PKCE) داخلی** — جریان خودکار برای Claude Code، Codex، Copilot، Kiro، Qwen و Qoder +- ** چند حساب OAuth ** - چندین حساب در هر ارائه دهنده از طریق استخراج رمز JWT/ID +- **OAuth LAN/Remote Fix** - تشخیص IP خصوصی برای `redirect_uri` + حالت دستی URL برای سرورهای راه دور +- **OAuth پشت Nginx** — از `window.location.origin` برای سازگاری با پراکسی معکوس استفاده می کند +- **راهنمای راه دور OAuth** - راهنمای گام به گام اعتبارنامه Google Cloud در VPS/Docker
-📊 9. "I don't know how much I'm spending or where" +📊 ۹. «نمی‌دانم چقدر و برای چه چیزی هزینه می‌کنم» -Developers use multiple paid providers but have no unified view of spending. Each provider has its own billing dashboard, but there's no consolidated view. Unexpected costs can pile up. +توسعه‌دهندگان از چندین ارائه‌دهنده پولی استفاده می‌کنند، اما دیدگاه واحدی از هزینه‌ها ندارند. هر ارائه دهنده داشبورد صورتحساب خود را دارد، اما هیچ نمای تلفیقی وجود ندارد. هزینه های غیرمنتظره می تواند روی هم انباشته شود. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **Cost Analytics Dashboard** — Per-token cost tracking and budget management per provider -- **Budget Limits per Tier** — Spending ceiling per tier that triggers automatic fallback -- **Per-Model Pricing Configuration** — Configurable prices per model -- **Usage Statistics Per API Key** — Request count and last-used timestamp per key -- **Analytics Dashboard** — Stat cards, model usage chart, provider table with success rates and latency +- **داشبورد تجزیه و تحلیل هزینه** - ردیابی هزینه هر توکن و مدیریت بودجه به ازای هر ارائه دهنده +- **محدودیت بودجه در هر ردیف** - سقف هزینه در هر ردیف که باعث بازگشت خودکار می شود +- **پیکربندی قیمت گذاری برای هر مدل** - قیمت های قابل تنظیم برای هر مدل +- **آمار استفاده به ازای کلید API** — تعداد درخواست و آخرین مهر زمانی استفاده شده در هر کلید +- **داشبورد تجزیه و تحلیل** - کارت های آمار، نمودار استفاده از مدل، جدول ارائه دهنده با میزان موفقیت و تاخیر
-🐛 10. "I can't diagnose errors and problems in AI calls" +🐛 ۱۰. «نمی‌توانم خطاها و مشکلات فراخوانی‌های هوش مصنوعی را عیب‌یابی کنم» -When a call fails, the dev doesn't know if it was a rate limit, expired token, wrong format, or provider error. Fragmented logs across different terminals. Without observability, debugging is trial-and-error. +وقتی یک تماس با شکست مواجه می‌شود، برنامه‌نویس نمی‌داند که آیا محدودیت نرخ، رمز منقضی شده، فرمت اشتباه یا خطای ارائه‌دهنده بوده است. لاگ های تکه تکه شده در پایانه های مختلف. بدون قابلیت مشاهده، اشکال زدایی آزمون و خطا است. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **Unified Logs Dashboard** — 4 tabs: Request Logs, Proxy Logs, Audit Logs, Console -- **Console Log Viewer** — Real-time terminal-style viewer with color-coded levels, auto-scroll, search, filter -- **SQLite Summary Logs** — Request and proxy log indexes stay queryable across restarts without loading large payload blobs into SQLite -- **Translator Playground** — 4 debugging modes: Playground (format translation), Chat Tester (round-trip), Test Bench (batch), Live Monitor (real-time) -- **Request Telemetry** — p50/p95/p99 latency + X-Request-Id tracing -- **File-Based Detail Artifacts** — App logs rotate by size, retention days, and archive count; detailed request/response payloads live in `DATA_DIR/call_logs/` and rotate independently of SQLite summaries -- **System Info Report** — `npm run system-info` generates `system-info.txt` with your full environment (Node version, OmniRoute version, OS, CLI tools, Docker/PM2 status). Attach it when reporting issues for instant triage. +- **داشبورد گزارش های یکپارچه** - 4 تب: گزارش های درخواست، گزارش های پروکسی، گزارش های حسابرسی، کنسول +- **نمایشگر ورود به سیستم** - نمایشگر به سبک ترمینال در زمان واقعی با سطوح رنگی، اسکرول خودکار، جستجو، فیلتر +- **SQLite Summary Logs** - فهرست درخواست و پروکسی در طول راه اندازی مجدد بدون بارگیری حباب های بار بزرگ در SQLite قابل پرس و جو می ماند. +- ** مترجم زمین بازی ** - 4 حالت اشکال زدایی: زمین بازی (ترجمه فرمت)، تستر چت (رفت و برگشت)، میز تست (دسته ای)، مانیتور زنده (زمان واقعی) +- **تله متری درخواست** — تأخیر p50/p95/p99 + ردیابی X-Request-Id +- ** مصنوعات جزئیات مبتنی بر فایل ** - سیاهههای مربوط به برنامه بر اساس اندازه، روزهای نگهداری و تعداد آرشیو می چرخند. بارهای درخواست/پاسخ دقیق در `DATA_DIR/call_logs/` زندگی می کنند و مستقل از خلاصه های SQLite می چرخند +- **گزارش اطلاعات سیستم** - `npm run system-info` `system-info.txt` را با محیط کامل شما تولید می کند (نسخه Node، نسخه OmniRoute، سیستم عامل، ابزار CLI، وضعیت Docker/PM2). هنگام گزارش مشکلات برای تریاژ فوری، آن را ضمیمه کنید.
-🏗️ 11. "Deploying and maintaining the gateway is complex" +🏗️ ۱۱. «استقرار و نگهداری درگاه پیچیده است» -Installing, configuring, and maintaining an AI proxy across different environments (local, VPS, Docker, cloud) is labor-intensive. Problems like hardcoded paths, `EACCES` on directories, port conflicts, and cross-platform builds add friction. +نصب، پیکربندی و نگهداری یک پروکسی هوش مصنوعی در محیط های مختلف (محلی، VPS، Docker، ابر) کار فشرده ای است. مشکلاتی مانند مسیرهای کدگذاری شده، `EACCES` در دایرکتوری‌ها، تداخل پورت‌ها، و ساخت‌های بین پلتفرمی باعث ایجاد اصطکاک می‌شوند. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **npm global install** — `npm install -g omniroute && omniroute` — done -- **Docker Multi-Platform** — AMD64 + ARM64 native (Apple Silicon, AWS Graviton, Raspberry Pi) -- **Docker Compose Profiles** — `base` (no CLI tools) and `cli` (with Claude Code, Codex, OpenClaw) -- **Electron Desktop App** — Native app for Windows/macOS/Linux with system tray, auto-start, offline mode -- **Split-Port Mode** — API and Dashboard on separate ports for advanced scenarios (reverse proxy, container networking) -- **Cloud Sync** — Config synchronization across devices via Cloudflare Workers -- **DB Backups** — Automatic backup, restore, export and import of all settings, with `DISABLE_SQLITE_AUTO_BACKUP` for externally managed backups +- ** نصب جهانی npm ** — `npm install -g omniroute && omniroute` — انجام شد +- **Docker چند پلتفرم** — AMD64 + ARM64 بومی (Apple Silicon، AWS Graviton، Raspberry Pi) +- **پروفایل‌های Docker Compose** — `base` (بدون ابزار CLI) و `cli` (همراه Claude Code، Codex و OpenClaw) +- **برنامه Electron Desktop** - برنامه بومی برای Windows/macOS/Linux با سینی سیستم، شروع خودکار، حالت آفلاین +- ** حالت Split-Port ** - API و داشبورد در پورت های جداگانه برای سناریوهای پیشرفته (پراکسی معکوس، شبکه کانتینری) +- **Cloud Sync** - همگام سازی پیکربندی بین دستگاه ها از طریق Cloudflare Workers +- **پشتیبان گیری از DB** - پشتیبان گیری خودکار، بازیابی، صادرات و واردات تمام تنظیمات، با `DISABLE_SQLITE_AUTO_BACKUP` برای پشتیبان گیری های مدیریت شده خارجی
-🌍 12. "The interface is English-only and my team doesn't speak English" +🌍 ۱۲. «رابط فقط انگلیسی است و تیم من انگلیسی صحبت نمی‌کند» -Teams in non-English-speaking countries, especially in Latin America, Asia, and Europe, struggle with English-only interfaces. Language barriers reduce adoption and increase configuration errors. +تیم های کشورهای غیر انگلیسی زبان، به ویژه در آمریکای لاتین، آسیا و اروپا، با رابط های فقط انگلیسی مبارزه می کنند. موانع زبان پذیرش را کاهش می دهد و خطاهای پیکربندی را افزایش می دهد. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **Dashboard i18n — 30 Languages** — All 500+ keys translated including Arabic, Bulgarian, Danish, German, Spanish, Finnish, French, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Malay, Dutch, Norwegian, Polish, Portuguese (PT/BR), Romanian, Russian, Slovak, Swedish, Thai, Ukrainian, Vietnamese, Chinese, Filipino, English -- **RTL Support** — Right-to-left support for Arabic and Hebrew -- **Multi-Language READMEs** — 30 complete documentation translations -- **Language Selector** — Globe icon in header for real-time switching +- **داشبورد i18n - 30 زبان** - تمام 500+ کلید ترجمه شده از جمله عربی، بلغاری، دانمارکی، آلمانی، اسپانیایی، فنلاندی، فرانسوی، عبری، هندی، مجارستانی، اندونزیایی، ایتالیایی، ژاپنی، کره ای، مالایی، هلندی، نروژی، لهستانی، پرتغالی (PT/BR)، رومانیایی، روسی، اسلواکی، سوئدی، تایلندی، اوکراینی، ویتنامی، چینی، فیلیپینی، انگلیسی +- ** پشتیبانی RTL ** - پشتیبانی از راست به چپ برای عربی و عبری +- ** README های چند زبانه ** - 30 ترجمه مستند کامل +- ** انتخابگر زبان ** - نماد کره در هدر برای تغییر زمان واقعی
-🔄 13. "I need more than chat — I need embeddings, images, audio" +🔄 ۱۳. «فراتر از چت نیاز دارم؛ به جاسازی، تصویر و صوت نیاز دارم» -AI isn't just chat completion. Devs need to generate images, transcribe audio, create embeddings for RAG, rerank documents, and moderate content. Each API has a different endpoint and format. +هوش مصنوعی فقط تکمیل چت نیست. توسعه دهندگان نیاز به تولید تصاویر، رونویسی صدا، ایجاد جاسازی برای RAG، رتبه بندی مجدد اسناد، و تعدیل محتوا دارند. هر API نقطه پایانی و قالب متفاوتی دارد. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **Embeddings** — `/v1/embeddings` with 6 providers and 9+ models -- **Image Generation** — `/v1/images/generations` with 10 providers and 20+ models (OpenAI, xAI, Together, Fireworks, Nebius, Hyperbolic, NanoBanana, Antigravity, SD WebUI, ComfyUI) -- **Text-to-Video** — `/v1/videos/generations` — ComfyUI (AnimateDiff, SVD) and SD WebUI -- **Text-to-Music** — `/v1/music/generations` — ComfyUI (Stable Audio Open, MusicGen) -- **Audio Transcription** — `/v1/audio/transcriptions` — Whisper + Nvidia NIM, HuggingFace, Qwen3 -- **Text-to-Speech** — `/v1/audio/speech` — ElevenLabs, Nvidia NIM, HuggingFace, Coqui, Tortoise, Qwen3, **Inworld**, **Cartesia**, **PlayHT**, + existing providers -- **Moderations** — `/v1/moderations` — Content safety checks -- **Reranking** — `/v1/rerank` — Document relevance reranking -- **Responses API** — Full `/v1/responses` support for Codex +- **جاسازی ها** — `/v1/embeddings` با 6 ارائه دهنده و 9+ مدل +- **تولید تصویر** — `/v1/images/generations` با 10 ارائه دهنده و 20+ مدل (OpenAI، xAI، Together، Fireworks، Nebius، Hyperbolic، NanoBanana، Antigravity، SD WebUI، ComfyUI) +- **تکست به ویدئو** - `/v1/videos/generations` - ComfyUI (AnimateDiff، SVD) و SD WebUI +- **تکست به موسیقی** - `/v1/music/generations` - ComfyUI (باز صدای پایدار، MusicGen) +- **رونویسی صوتی** - `/v1/audio/transcriptions` - Whisper + Nvidia NIM، HuggingFace، Qwen3 +- **تکست به گفتار** — `/v1/audio/speech` — ElevenLabs، Nvidia NIM، HuggingFace، Coqui، Tortoise، Qwen3، **Inworld**، **Cartesia**، **PlayHT**، + ارائه دهندگان موجود +- ** تعدیل ها ** - `/v1/moderations` - بررسی های ایمنی محتوا +- **رتبه‌بندی مجدد** - `/v1/rerank` - رتبه‌بندی مجدد مربوط به سند +- **پاسخ API** — پشتیبانی کامل از `/v1/responses` برای Codex
-🧪 14. "I have no way to test and compare quality across models" +🧪 ۱۴. «راهی برای آزمودن و مقایسهٔ کیفیت مدل‌ها ندارم» -Developers want to know which model is best for their use case — code, translation, reasoning — but comparing manually is slow. No integrated eval tools exist. +توسعه‌دهندگان می‌خواهند بدانند کدام مدل برای موارد استفاده آنها بهترین است - کد، ترجمه، استدلال - اما مقایسه دستی کند است. هیچ ابزار ارزیابی یکپارچه وجود ندارد. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **LLM Evaluations** — Golden set testing with 10 pre-loaded cases covering greetings, math, geography, code generation, JSON compliance, translation, markdown, safety refusal -- **4 Match Strategies** — `exact`, `contains`, `regex`, `custom` (JS function) -- **Translator Playground Test Bench** — Batch testing with multiple inputs and expected outputs, cross-provider comparison -- **Chat Tester** — Full round-trip with visual response rendering -- **Live Monitor** — Real-time stream of all requests flowing through the proxy +- ** ارزیابی های LLM ** - تست مجموعه طلایی با 10 مورد از پیش بارگذاری شده که احوالپرسی، ریاضی، جغرافیا، تولید کد، انطباق با JSON، ترجمه، علامت گذاری، امتناع ایمنی را پوشش می دهد +- **4 استراتژی مطابقت ** — `exact`، `contains`، `regex`، `custom` (عملکرد JS) +- **نیمکت تست مترجم زمین بازی** - تست دسته ای با ورودی های متعدد و خروجی های مورد انتظار، مقایسه بین ارائه دهندگان +- **تستر چت** - رفت و برگشت کامل با رندر پاسخ بصری +- ** مانیتور زنده ** - جریان بیدرنگ تمام درخواست هایی که از طریق پروکسی جریان می یابد
-📈 15. "I need to scale without losing performance" +📈 ۱۵. «باید بدون افت کارایی مقیاس‌پذیر شوم» -As request volume grows, without caching the same questions generate duplicate costs. Without idempotency, duplicate requests waste processing. Per-provider rate limits must be respected. +با افزایش حجم درخواست، بدون ذخیره سازی در حافظه پنهان، همان سوالات هزینه های تکراری ایجاد می کنند. بدون ناتوانی، درخواست های تکراری پردازش زباله. محدودیت های نرخ هر ارائه دهنده باید رعایت شود. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **Semantic Cache** — Two-tier cache (signature + semantic) reduces cost and latency -- **Request Idempotency** — 5s deduplication window for identical requests -- **Rate Limit Detection** — Per-provider RPM, min gap, and max concurrent tracking -- **Request Queue & Pacing** — Configurable queue, pacing, and concurrency defaults in Settings → Resilience -- **API Key Validation Cache** — 3-tier cache for production performance -- **Health Dashboard with Telemetry** — p50/p95/p99 latency, cache stats, uptime +- ** کش معنایی ** - کش دو لایه (امضا + معنایی) هزینه و تأخیر را کاهش می دهد +- ** درخواست Idempotency ** - پنجره deduplication 5s برای درخواست های یکسان +- **تشخیص محدودیت نرخ** - RPM هر ارائه دهنده، حداقل فاصله و حداکثر ردیابی همزمان +- **درخواست صف و سرعت** - پیش فرض های صف، سرعت و همزمانی قابل تنظیم در تنظیمات → انعطاف پذیری +- ** حافظه پنهان اعتبارسنجی کلید API ** - حافظه نهان 3 لایه برای عملکرد تولید +- ** داشبورد سلامت با تله متری ** - تأخیر p50/p95/p99، آمار حافظه پنهان، زمان آپدیت
-🤖 16. "I want to control model behavior globally" +🤖 ۱۶. «می‌خواهم رفتار مدل را به‌صورت سراسری کنترل کنم» -Developers who want all responses in a specific language, with a specific tone, or want to limit reasoning tokens. Configuring this in every tool/request is impractical. +توسعه دهندگانی که همه پاسخ ها را به زبانی خاص، با لحن خاصی می خواهند یا می خواهند نشانه های استدلال را محدود کنند. پیکربندی این در هر ابزار/درخواست غیرعملی است. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **System Prompt Injection** — Global prompt applied to all requests -- **Thinking Budget Validation** — Reasoning token allocation control per request (passthrough, auto, custom, adaptive) -- **9 Routing Strategies** — Global strategies that determine how requests are distributed -- **Wildcard Router** — `provider/*` patterns route dynamically to any provider -- **Combo Enable/Disable Toggle** — Toggle combos directly from the dashboard -- **Manual Combo Ordering** — Drag combo cards by handle and persist the order in SQLite -- **Provider Toggle** — Enable/disable all connections for a provider with one click -- **Blocked Providers** — Exclude specific providers from `/v1/models` listing +- **تزریق سریع سیستم** - اعلان جهانی برای همه درخواست ها اعمال می شود +- ** اعتبارسنجی بودجه فکری ** - کنترل تخصیص رمز استدلال در هر درخواست (گذرا، خودکار، سفارشی، تطبیقی) +- **9 استراتژی مسیریابی** - استراتژی های جهانی که نحوه توزیع درخواست ها را تعیین می کند +- **مسیریاب Wildcard** - الگوهای `provider/*` به صورت پویا به هر ارائه دهنده ای می روند +- ** Combo Enable/Disable Toggle** - جابجایی ترکیبی به طور مستقیم از داشبورد +- ** سفارش دستی ترکیبی ** - کارت های ترکیبی را با دسته بکشید و سفارش را در SQLite ادامه دهید +- **تغییر ارائه دهنده** - همه اتصالات یک ارائه دهنده را با یک کلیک فعال/غیرفعال کنید +- **ارائه دهندگان مسدود شده** - ارائه دهندگان خاص را از لیست `/v1/models` حذف کنید
-🧰 17. "I need MCP tools as first-class product capabilities" +🧰 ۱۷. «به ابزارهای MCP به‌عنوان قابلیت‌های اصلی محصول نیاز دارم» -Many AI gateways expose MCP only as a hidden implementation detail. Teams need a visible, manageable operation layer. +بسیاری از دروازه‌های هوش مصنوعی MCP را تنها به عنوان یک جزئیات پیاده‌سازی پنهان نشان می‌دهند. تیم ها به یک لایه عملیاتی قابل کنترل و قابل مشاهده نیاز دارند. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- MCP appears in the dashboard navigation and endpoint protocol tab -- Dedicated MCP management page with process, tools, scopes, and audit -- Built-in quick-start for `omniroute --mcp` and client onboarding +- MCP در برگه ناوبری داشبورد و پروتکل نقطه پایان ظاهر می شود +- صفحه مدیریت اختصاصی MCP با فرآیند، ابزار، دامنه و ممیزی +- راه اندازی سریع داخلی برای `omniroute --mcp` و نصب مشتری
-🧠 18. "I need A2A orchestration with sync + stream task paths" +🧠 ۱۸. «به ارکستراسیون A2A با مسیرهای وظیفهٔ همگام و جریانی نیاز دارم» -Agent workflows need both direct replies and long-running streamed execution with lifecycle control. +گردش کار عامل هم به پاسخ های مستقیم و هم به اجرای جریانی طولانی مدت با کنترل چرخه حیات نیاز دارد. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- A2A JSON-RPC endpoint (`POST /a2a`) with `message/send` and `message/stream` -- SSE streaming with terminal state propagation -- Task lifecycle APIs for `tasks/get` and `tasks/cancel` +- نقطه پایانی A2A JSON-RPC (`POST /a2a`) با `message/send` و `message/stream` +- پخش جریانی SSE با انتشار حالت ترمینال +- APIهای چرخه حیات وظیفه برای `tasks/get` و `tasks/cancel`
-🛰️ 19. "I need real MCP process health, not guessed status" +🛰️ ۱۹. «به سلامت واقعی فرایند MCP نیاز دارم، نه وضعیت حدسی» -Operational teams need to know if MCP is actually alive, not just whether an API is reachable. +تیم های عملیاتی باید بدانند که آیا MCP واقعاً زنده است یا نه، نه فقط اینکه آیا API قابل دسترسی است یا خیر. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- Runtime heartbeat file with PID, timestamps, transport, tool count, and scope mode -- MCP status API combining heartbeat + recent activity -- UI status cards for process/uptime/heartbeat freshness +- فایل ضربان قلب در زمان اجرا با PID، مهرهای زمانی، حمل و نقل، شمارش ابزار و حالت دامنه +- وضعیت MCP API ترکیبی از ضربان قلب + فعالیت اخیر +- کارت های وضعیت رابط کاربری برای تازگی فرآیند/تایم/ضربان قلب
-📋 20. "I need auditable MCP tool execution" +📋 ۲۰. «به اجرای قابل‌ممیزی ابزارهای MCP نیاز دارم» -When tools mutate config or trigger ops actions, teams need forensic traceability. +هنگامی که ابزارها پیکربندی را تغییر می دهند یا اقدامات عملیاتی را آغاز می کنند، تیم ها به قابلیت ردیابی قانونی نیاز دارند. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- SQLite-backed audit logging for MCP tool calls -- Filters by tool, success/failure, API key, and pagination -- Dashboard audit table + stats endpoints for automation +- ثبت حسابرسی با پشتیبانی SQLite برای تماس های ابزار MCP +- فیلترها بر اساس ابزار، موفقیت/شکست، کلید API و صفحه بندی +- جدول حسابرسی داشبورد + نقاط پایانی آمار برای اتوماسیون
-🔐 21. "I need scoped MCP permissions per integration" +🔐 ۲۱. «برای هر یکپارچه‌سازی، به مجوزهای محدوده‌دار MCP نیاز دارم» -Different clients should have least-privilege access to tool categories. +مشتریان مختلف باید کمترین امتیاز را به دسته های ابزار داشته باشند. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- 32 granular MCP scopes for controlled tool access -- Scope enforcement and visibility in MCP management UI -- Safe default posture for operational tooling +- 32 اسکوپ گرانول MCP برای دسترسی کنترل شده به ابزار +- اجرای محدوده و دید در رابط کاربری مدیریت MCP +- وضعیت پیش فرض ایمن برای ابزار عملیاتی
-⚙️ 22. "I need operational controls without redeploying" +⚙️ ۲۲. «به کنترل‌های عملیاتی بدون استقرار مجدد نیاز دارم» -Teams need quick runtime changes during incidents or cost events. +تیم ها به تغییرات سریع در زمان اجرا در طول حوادث یا رویدادهای هزینه نیاز دارند. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- Switch combo activation directly from MCP dashboard -- Tune queue, cooldown, breaker, and wait settings from the dedicated Resilience page -- Review live provider breaker state from the Health dashboard +- فعال سازی ترکیبی را مستقیماً از داشبورد MCP تغییر دهید +- تنظیمات صف، خنک کننده، شکن و انتظار را از صفحه اختصاصی Resilience تنظیم کنید +- وضعیت قطع کننده ارائه دهنده زنده را از داشبورد Health مرور کنید
-🔄 23. "I need live A2A task lifecycle visibility and cancellation" +🔄 ۲۳. «به مشاهدهٔ زنده و لغو چرخهٔ حیات وظایف A2A نیاز دارم» -Without lifecycle visibility, task incidents become hard to triage. +بدون دید چرخه حیات، تریاژ حوادث کار سخت می شود. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- Task listing/filtering by state/skill with pagination -- Drill-down on task metadata, events, and artifacts -- Task cancellation endpoint and UI action with confirmation +- فهرست کار/فیلتر کردن بر اساس وضعیت/مهارت با صفحه بندی +- متادیتاهای وظیفه، رویدادها و مصنوعات را بررسی کنید +- نقطه پایانی لغو کار و اقدام UI با تأیید
-🌊 24. "I need active stream metrics for A2A load" +🌊 ۲۴. «برای بار A2A به معیارهای جریان فعال نیاز دارم» -Streaming workflows require operational insight into concurrency and live connections. +جریان کار مستلزم بینش عملیاتی در مورد همزمانی و اتصالات زنده است. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- Active stream counters integrated into A2A status -- Last task timestamp and per-state counts -- A2A dashboard cards for real-time ops monitoring +- شمارنده های جریان فعال در وضعیت A2A یکپارچه شده است +- آخرین مهر زمان کار و تعداد هر ایالت +- کارت های داشبورد A2A برای نظارت بر عملیات در زمان واقعی
-🪪 25. "I need standard agent discovery for clients" +🪪 ۲۵. «به کشف استاندارد عامل برای کلاینت‌ها نیاز دارم» -External clients and orchestrators need machine-readable metadata for onboarding. +مشتریان خارجی و ارکستراتورها برای سوار شدن به ابرداده قابل خواندن توسط ماشین نیاز دارند. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- Agent Card exposed at `/.well-known/agent.json` -- Capabilities and skills shown in management UI -- A2A status API includes discovery metadata for automation +- کارت نماینده در `/.well-known/agent.json` در معرض دید قرار گرفت +- قابلیت ها و مهارت های نشان داده شده در رابط کاربری مدیریت +- وضعیت A2A API شامل ابرداده های کشف برای اتوماسیون است
-🧭 26. "I need protocol discoverability in the product UX" +🧭 ۲۶. «به کشف‌پذیری پروتکل در تجربهٔ کاربری محصول نیاز دارم» -If users cannot discover protocol surfaces, adoption and support quality drop. +اگر کاربران نتوانند سطوح پروتکل را کشف کنند، کیفیت پذیرش و پشتیبانی کاهش می یابد. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- Consolidated **Endpoints** page with tabs for Proxy, MCP, A2A, and API Endpoints -- Inline service status toggles (Online/Offline) for MCP and A2A -- Links from overview to dedicated management tabs +- صفحه تلفیقی **Endpoints** با برگه‌های Proxy، MCP، A2A، و API +- تغییر وضعیت سرویس درون خطی (آنلاین/آفلاین) برای MCP و A2A +- پیوند از نمای کلی به برگه های مدیریت اختصاصی
-🧪 27. "I need end-to-end protocol validation with real clients" +🧪 ۲۷. «به اعتبارسنجی سرتاسری پروتکل با کلاینت‌های واقعی نیاز دارم» -Mock tests are not enough to validate protocol compatibility before release. +تست های ساختگی برای تایید سازگاری پروتکل قبل از انتشار کافی نیستند. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- E2E suite that boots app and uses real MCP SDK client transport -- A2A client tests for discovery, send, stream, get, and cancel flows -- Cross-check assertions against MCP audit and A2A tasks APIs +- مجموعه E2E که برنامه را بوت می کند و از حمل و نقل مشتری واقعی MCP SDK استفاده می کند +- تست مشتری A2A برای کشف، ارسال، پخش، دریافت و لغو جریان ها +- بررسی متقاطع ادعاها علیه MCP ممیزی و API وظایف A2A
-📡 28. "I need unified observability across all interfaces" +📡 ۲۸. «به مشاهده‌پذیری یکپارچه در همهٔ رابط‌ها نیاز دارم» -Splitting observability by protocol creates blind spots and longer MTTR. +تقسیم قابلیت مشاهده توسط پروتکل باعث ایجاد نقاط کور و MTTR طولانی تر می شود. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- Unified dashboards/logs/analytics in one product -- Health + audit + request telemetry across OpenAI, MCP, and A2A layers -- Operational APIs for status and automation +- داشبورد / سیاهههای مربوط / تجزیه و تحلیل یکپارچه در یک محصول +- سلامت + ممیزی + درخواست تله متری در لایه های OpenAI، MCP، و A2A +- API های عملیاتی برای وضعیت و اتوماسیون
-💼 29. "I need one runtime for proxy + tools + agent orchestration" +💼 ۲۹. «برای پروکسی، ابزارها و ارکستراسیون عامل به یک محیط اجرا نیاز دارم» -Running many separate services increases operational cost and failure modes. +اجرای بسیاری از خدمات جداگانه هزینه عملیاتی و حالت های خرابی را افزایش می دهد. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- OpenAI-compatible proxy, MCP server, and A2A server in one stack -- Shared auth, resilience, data store, and observability -- Consistent policy model across all interaction surfaces +- پروکسی سازگار با OpenAI، سرور MCP و سرور A2A در یک پشته +- اعتبار مشترک، انعطاف پذیری، ذخیره داده ها و قابلیت مشاهده +- مدل خط مشی سازگار در تمام سطوح تعامل
-🚀 30. "I need to ship agentic workflows without glue-code sprawl" +🚀 ۳۰. «می‌خواهم گردش‌کارهای عامل‌محور را بدون پراکندگی کدهای اتصال‌دهنده منتشر کنم» -Teams lose velocity when stitching multiple ad-hoc services and scripts. +تیم ها هنگام دوخت چندین سرویس ad-hoc و اسکریپت سرعت خود را از دست می دهند. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- Unified endpoint strategy for clients and agents -- Built-in protocol management UIs and smoke validation paths -- Production-ready foundations (security, logging, resilience, backup) +- استراتژی نقطه پایانی یکپارچه برای مشتریان و نمایندگان +- رابط های کاربری داخلی مدیریت پروتکل و مسیرهای اعتبارسنجی دود +- پایه های آماده تولید (امنیت، ورود به سیستم، انعطاف پذیری، پشتیبان گیری)
-📚 31. "My long sessions crash with 'context_length_exceeded' limits" +📚 ۳۱. «نشست‌های طولانی من با محدودیت «context_length_exceeded» متوقف می‌شوند» -During deep debugging, long histories with tool results quickly exceed provider token windows, causing failed requests and orphaned context. +در طول اشکال‌زدایی عمیق، تاریخچه‌های طولانی با نتایج ابزار به سرعت از پنجره‌های رمز ارائه‌دهنده فراتر می‌روند، که باعث درخواست‌های ناموفق و زمینه بی‌اطلاعی می‌شود. -**How OmniRoute solves it:** +** چگونه OmniRoute آن را حل می کند:** -- **Proactive Context Compression** — Evaluates token budgets before the request hits upstream and proactively prunes old conversation history with a smart binary-search mechanism. -- **Structural Integrity Guards** — Automatically tracks explicit `tool_use` definitions and ensures that if a tool input is truncated, its corresponding `tool_result` is also safely removed, preventing API validation errors. -- **Multi-Layer Dropping** — Progressively drops system messages, regular messages, and finally enforces strict length limits without breaking conversational logic. +- ** فشرده سازی متن پیشگیرانه ** - قبل از اینکه درخواست به بالادست برسد، بودجه توکن ها را ارزیابی می کند و به طور فعال تاریخچه مکالمات قدیمی را با مکانیزم جستجوی باینری هوشمند حذف می کند. +- ** محافظ یکپارچگی ساختاری** - تعاریف صریح `tool_use` را به طور خودکار ردیابی می کند و تضمین می کند که اگر ورودی ابزار کوتاه شود، `tool_result` مربوطه آن نیز با خیال راحت حذف می شود و از خطاهای اعتبارسنجی API جلوگیری می کند. +- **کاهش چند لایه** - به تدریج پیام های سیستمی، پیام های معمولی را حذف می کند و در نهایت محدودیت های طولانی مدت را بدون نقض منطق مکالمه اعمال می کند.
-### Example Playbooks (Integrated Use Cases) +### نمونه کتابهای راهنما (مورد استفاده یکپارچه) -**Playbook A: Maximize paid subscription + cheap backup** +**Playbook A: اشتراک پولی را به حداکثر برسانید + پشتیبان گیری ارزان** ```txt Combo: "maximize-claude" @@ -696,7 +696,7 @@ Monthly cost: $20 + small backup spend Outcome: higher quality, near-zero interruption ``` -**Playbook B: Zero-cost coding stack** +**راهنمای B: پشته کدگذاری بدون هزینه** ```txt Combo: "free-access" @@ -707,7 +707,7 @@ Monthly cost: $0 Outcome: broader free-access fallback; upstream availability is not guaranteed ``` -**Playbook C: 24/7 always-on fallback chain** +**کتاب راهنما C: زنجیره بازگشتی 24 ساعته همیشه فعال** ```txt Combo: "multi-layer-fallback" @@ -720,7 +720,7 @@ Combo: "multi-layer-fallback" Outcome: deep fallback depth for deadline-critical workloads ``` -**Playbook D: Agent ops with MCP + A2A** +**راهنمای D: عملیات عامل با MCP + A2A** ```txt 1) Start MCP transport (`omniroute --mcp`) for tool-driven operations @@ -731,57 +731,57 @@ Outcome: deep fallback depth for deadline-critical workloads --- -## 🆓 Start Free — Zero Configuration Cost +## 🆓 شروع رایگان — هزینه پیکربندی صفر -> Setup AI coding in minutes at **$0/month**. Connect these free accounts and use the built-in **Free Stack** combo. +> کدگذاری هوش مصنوعی را در چند دقیقه با **0 دلار در ماه** تنظیم کنید. این حساب‌های رایگان را متصل کنید و از ترکیب داخلی **پشته رایگان** استفاده کنید. -| Step | Action | Providers Unlocked | +| مرحله | اقدام | قفل ارائه دهندگان | | ---- | -------------------------------------------------- | ------------------------------------------------------------------ | -| 1 | Connect **Kiro** (AWS Builder ID OAuth) | Claude Sonnet 4.5, Haiku 4.5 — provider/account limits apply | -| 2 | Connect **Qoder** (Google OAuth) | kimi-k2-thinking, qwen3-coder-plus, deepseek-r1... — provider/account limits apply | -| 3 | Connect **Qwen** (Device Code) | qwen3-coder-plus, qwen3-coder-flash... — provider/account limits apply | -| 4 | `/dashboard/combos` → **Free Stack ($0)** template | Round-robin all free providers automatically | +| 1 | اتصال **Kiro** (شناسه سازنده AWS OAuth) | Claude Sonnet 4.5، Haiku 4.5 — محدودیت های ارائه دهنده/حساب اعمال می شود | +| 2 | اتصال **Qoder** (Google OAuth) | kimi-k2-thinking، qwen3-coder-plus، deepseek-r1... — محدودیت های ارائه دهنده/حساب اعمال می شود | +| 3 | اتصال **Qwen** (کد دستگاه) | qwen3-coder-plus، qwen3-coder-flash... — محدودیت های ارائه دهنده/حساب اعمال می شود | +| 4 | قالب `/dashboard/combos` → **پشته رایگان (0$)** | همه ارائه دهندگان رایگان را بصورت خودکار | -**Point any IDE/CLI to:** `http://localhost:20128/v1` · API Key: `any-string` · Done. +**کلید IDE/CLI را به:** `http://localhost:20128/v1` · API کلید: `any-string` · انجام شد. -> **Optional extra coverage (current terms apply):** Groq, NVIDIA NIM, Cerebras, LongCat and Cloudflare Workers AI can provide free access or signup credits where currently listed. Quotas, models, accounts, regions and provider terms can change; see [`FREE_TIERS.md`](../../reference/FREE_TIERS.md). +> **پوشش اضافی اختیاری (شرایط فعلی اعمال می‌شود):** Groq، NVIDIA NIM، Cerebras، LongCat و Cloudflare Workers AI می‌تواند اعتبار رایگان را در مکان‌هایی که در حال حاضر فهرست شده است ارائه دهد. سهمیه ها، مدل ها، حساب ها، مناطق و شرایط ارائه دهنده می توانند تغییر کنند. [`FREE_TIERS.md`](../../reference/FREE_TIERS.md) را ببینید. -## Inicio Rápido +## اینیسیو راپیدو -### 1) Install and run +### 1) نصب و اجرا کنید ```bash npm install -g omniroute omniroute ``` -> **pnpm users:** Pass `--allow-build` at install time to enable native build scripts required by `better-sqlite3` and `@swc/core` (the `approve-builds -g` command is not supported for global installs on pnpm v11): +> **کاربران pnpm:** در زمان نصب `--allow-build` را برای فعال کردن اسکریپت های ساخت بومی مورد نیاز `better-sqlite3` و `@swc/core` ارسال کنید (دستور `approve-builds -g` برای نصب های جهانی در pnpm v11 پشتیبانی نمی شود): > > ```bash > pnpm add -g omniroute@latest --allow-build=better-sqlite3 --allow-build=@swc/core > omniroute > ``` -Dashboard opens at `http://localhost:20128` and API base URL is `http://localhost:20128/v1`. +داشبورد در `http://localhost:20128` باز می شود و پایه API URL `http://localhost:20128/v1` است. -#### Arch Linux (AUR) +#### آرچ لینوکس (AUR) -Arch Linux users can install the [AUR package](https://aur.archlinux.org/packages/omniroute-bin), which installs OmniRoute and provides a systemd user service: +کاربران آرچ لینوکس می توانند [بسته AUR](https://aur.archlinux.org/packages/omniroute-bin) را نصب کنند که OmniRoute را نصب می کند و یک سرویس کاربر سیستمی ارائه می دهد: ```bash yay -S omniroute-bin systemctl --user enable --now omniroute.service ``` -| Command | Description | +| فرمان | توضیحات | | ----------------------- | ----------------------------------------------------------- | -| `omniroute` | Start server (`PORT=20128`, API and dashboard on same port) | -| `omniroute --port 3000` | Set canonical/API port to 3000 | -| `omniroute --mcp` | Start MCP server (stdio transport) | -| `omniroute --no-open` | Don't auto-open browser | -| `omniroute --help` | Show help | +| `omniroute` | راه اندازی سرور (`PORT=20128`، API و داشبورد در همان پورت) | +| `omniroute --port 3000` | پورت canonical/API را روی 3000 | تنظیم کنید +| `omniroute --mcp` | راه اندازی سرور MCP (stdio transport) | +| `omniroute --no-open` | مرورگر خودکار باز نشود | +| `omniroute --help` | نمایش کمک | -Optional split-port mode: +حالت اسپلیت پورت اختیاری: ```bash PORT=20128 DASHBOARD_PORT=20129 omniroute @@ -789,63 +789,63 @@ PORT=20128 DASHBOARD_PORT=20129 omniroute # Dashboard: http://localhost:20129 ``` -### 2) Uninstalling +### 2) حذف نصب -When you no longer need OmniRoute, we provide two quick scripts for a clean removal: +هنگامی که دیگر نیازی به OmniRoute ندارید، ما دو اسکریپت سریع برای حذف تمیز ارائه می دهیم: -| Command | Action | +| فرمان | اقدام | | ------------------------ | ----------------------------------------------------------------------------------- | -| `npm run uninstall` | Removes the system app but **keeps your DB and configurations** in `~/.omniroute`. | -| `npm run uninstall:full` | Removes the app AND permanently **erases all configurations, keys, and databases**. | +| `npm run uninstall` | برنامه سیستم را حذف می کند اما **DB و تنظیمات** شما را در `~/.omniroute` نگه می دارد. | +| `npm run uninstall:full` | برنامه را حذف می کند و برای همیشه **همه پیکربندی ها، کلیدها و پایگاه داده ها را پاک می کند**. | -> Note: To run these commands, navigate to the OmniRoute project folder (if you cloned it) and run them. Alternatively, if globally installed, you can simply run `npm uninstall -g omniroute`. +> توجه: برای اجرای این دستورات، به پوشه پروژه OmniRoute (اگر آن را شبیه سازی کرده اید) بروید و آنها را اجرا کنید. از طرف دیگر، اگر به صورت سراسری نصب شده باشد، می توانید به سادگی `npm uninstall -g omniroute` را اجرا کنید. -### Long-Running Streaming Timeouts +### وقفه های طولانی مدت استریم -For most deployments, you only need: +برای اکثر استقرارها، فقط نیاز دارید: -| Variable | Default | Purpose | +| متغیر | پیش فرض | هدف | | ------------------------ | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -| `REQUEST_TIMEOUT_MS` | `600000` | Shared baseline for upstream response-start timeout, hidden Undici timeouts, TLS fingerprint requests, and API bridge request/proxy timeouts | -| `STREAM_IDLE_TIMEOUT_MS` | inherits `REQUEST_TIMEOUT_MS` | Maximum gap between streaming chunks before OmniRoute aborts the SSE stream | +| `REQUEST_TIMEOUT_MS` | `600000` | خط پایه مشترک برای مهلت زمانی شروع پاسخ بالادست، مهلت زمانی پنهان Undici، درخواست‌های اثر انگشت TLS و زمان‌بندی درخواست پل/پراکسی API | +| `STREAM_IDLE_TIMEOUT_MS` | به ارث می برد `REQUEST_TIMEOUT_MS` | حداکثر فاصله بین تکه های جریان قبل از اینکه OmniRoute جریان SSE را لغو کند | -Backward compatibility is preserved: existing `FETCH_TIMEOUT_MS`, `API_BRIDGE_PROXY_TIMEOUT_MS`, and other per-layer timeout vars still work and override the shared baseline. +سازگاری به عقب حفظ می شود: `FETCH_TIMEOUT_MS`، `API_BRIDGE_PROXY_TIMEOUT_MS`، و سایر متغیرهای وقفه زمانی هر لایه هنوز کار می کنند و خط پایه مشترک را لغو می کنند. -For Claude Code-compatible upstreams (`anthropic-compatible-cc-*`), OmniRoute also derives the outbound `X-Stainless-Timeout` header from the resolved fetch timeout so provider-side read timeouts stay aligned with your env configuration. +برای Claude بالادستی سازگار با کد (`anthropic-compatible-cc-*`)، OmniRoute همچنین سرصفحه خروجی `X-Stainless-Timeout` را از بازه زمانی واکشی حل‌شده استخراج می‌کند، بنابراین زمان‌بندی خواندن سمت ارائه‌دهنده با پیکربندی env شما همسو می‌شود. -For third-party Claude Code-compatible reverse proxies, OmniRoute keeps the default -`anthropic-beta` set conservative and, when `Client Cache Control` is left on `Auto`, -only forwards client-provided `cache_control` markers. If the request does not include -`cache_control`, OmniRoute does not inject bridge-owned markers. +برای پراکسی های معکوس Claude شخص ثالث سازگار با کد، OmniRoute پیش فرض را نگه می دارد +`anthropic-beta` محافظه کارانه تنظیم می شود و وقتی `Client Cache Control` روی `Auto` باقی می ماند، +فقط نشانگرهای `cache_control` ارائه شده توسط مشتری را فوروارد می کند. اگر درخواست شامل نمی شود +`cache_control`، OmniRoute نشانگرهای متعلق به پل را تزریق نمی کند. -Advanced overrides are available if you need finer control: +در صورت نیاز به کنترل دقیق تر، لغو پیشرفته در دسترس است: -| Variable | Default | Purpose | +| متغیر | پیش فرض | هدف | | ---------------------------------------- | ------------------------------------------ | -------------------------------------------------------------------- | -| `FETCH_TIMEOUT_MS` | inherits `REQUEST_TIMEOUT_MS` | Upstream response-start timeout used until response headers arrive | -| `FETCH_HEADERS_TIMEOUT_MS` | inherits `FETCH_TIMEOUT_MS` | Undici time limit for receiving upstream response headers | -| `FETCH_BODY_TIMEOUT_MS` | inherits `FETCH_TIMEOUT_MS` | Undici time limit between upstream body chunks (`0` disables it) | -| `FETCH_CONNECT_TIMEOUT_MS` | `30000` | Undici TCP connect timeout | -| `FETCH_KEEPALIVE_TIMEOUT_MS` | `4000` | Undici idle keep-alive socket timeout | -| `TLS_CLIENT_TIMEOUT_MS` | inherits `FETCH_TIMEOUT_MS` | Timeout for TLS fingerprint requests made through `wreq-js` | -| `API_BRIDGE_PROXY_TIMEOUT_MS` | inherits `REQUEST_TIMEOUT_MS` or `600000` | Timeout for `/v1` proxy forwarding from API port to dashboard port | -| `API_BRIDGE_SERVER_REQUEST_TIMEOUT_MS` | `max(API_BRIDGE_PROXY_TIMEOUT_MS, 300000)` | Incoming request timeout on the API bridge server | -| `API_BRIDGE_SERVER_HEADERS_TIMEOUT_MS` | `60000` | Incoming header timeout on the API bridge server | -| `API_BRIDGE_SERVER_KEEPALIVE_TIMEOUT_MS` | `5000` | Keep-alive timeout on the API bridge server | -| `API_BRIDGE_SERVER_SOCKET_TIMEOUT_MS` | `0` | Socket inactivity timeout on the API bridge server (`0` disables it) | +| `FETCH_TIMEOUT_MS` | به ارث می برد `REQUEST_TIMEOUT_MS` | زمان پایان پاسخ-شروع بالادستی تا رسیدن سرصفحه های پاسخ استفاده می شود | +| `FETCH_HEADERS_TIMEOUT_MS` | به ارث می برد `FETCH_TIMEOUT_MS` | محدودیت زمانی Undici برای دریافت سرصفحه های پاسخ بالادست | +| `FETCH_BODY_TIMEOUT_MS` | به ارث می برد `FETCH_TIMEOUT_MS` | محدودیت زمانی Undici بین تکه های بدنه بالادست (`0` آن را غیرفعال می کند) | +| `FETCH_CONNECT_TIMEOUT_MS` | `30000` | زمان اتصال Undici TCP | +| `FETCH_KEEPALIVE_TIMEOUT_MS` | `4000` | مهلت زمانی سوکت بیکار نگه داشتن زنده Undici | +| `TLS_CLIENT_TIMEOUT_MS` | به ارث می برد `FETCH_TIMEOUT_MS` | مهلت زمانی برای درخواست های اثر انگشت TLS که از طریق `wreq-js` | +| `API_BRIDGE_PROXY_TIMEOUT_MS` | به ارث می برد `REQUEST_TIMEOUT_MS` یا `600000` | مهلت زمانی برای ارسال پروکسی `/v1` از پورت API به پورت داشبورد | +| `API_BRIDGE_SERVER_REQUEST_TIMEOUT_MS` | `max(API_BRIDGE_PROXY_TIMEOUT_MS, 300000)` | زمان درخواست ورودی در سرور پل API | +| `API_BRIDGE_SERVER_HEADERS_TIMEOUT_MS` | `60000` | مهلت زمانی هدر ورودی در سرور پل API | +| `API_BRIDGE_SERVER_KEEPALIVE_TIMEOUT_MS` | `5000` | وقفه ماندن زنده در سرور پل API | +| `API_BRIDGE_SERVER_SOCKET_TIMEOUT_MS` | `0` | پایان زمان عدم فعالیت سوکت در سرور پل API (`0` آن را غیرفعال می کند) | -For streaming requests, `FETCH_TIMEOUT_MS` only covers connection setup / waiting for the first upstream response. Once the stream is active, OmniRoute will only abort on an actual stall (`STREAM_IDLE_TIMEOUT_MS`) or Undici body inactivity (`FETCH_BODY_TIMEOUT_MS`). +برای درخواست‌های پخش جریانی، `FETCH_TIMEOUT_MS` فقط راه‌اندازی اتصال / انتظار برای اولین پاسخ بالادستی را پوشش می‌دهد. پس از فعال شدن جریان، OmniRoute فقط در حالت توقف واقعی (`STREAM_IDLE_TIMEOUT_MS`) یا عدم فعالیت بدنه Undici (`FETCH_BODY_TIMEOUT_MS`) متوقف می شود. -If you run OmniRoute behind Nginx, Caddy, Cloudflare, or another reverse proxy, make sure the proxy -timeouts are also higher than your OmniRoute stream/fetch timeouts. +اگر OmniRoute را پشت Nginx، Caddy، Cloudflare یا یک پراکسی معکوس دیگر اجرا می‌کنید، از پراکسی مطمئن شوید +زمان‌بندی‌ها نیز بیشتر از زمان‌های زمانی پخش/واکشی OmniRoute شما هستند. -### 2) Connect providers and create your API key +### 2) ارائه دهندگان را متصل کنید و کلید API خود را ایجاد کنید -1. Open Dashboard → `Providers` and connect at least one provider (OAuth or API key). -2. Open Dashboard → `Endpoints` and create an API key. -3. (Optional) Open Dashboard → `Combos` and set your fallback chain. +1. داشبورد → `Providers` را باز کنید و حداقل یک ارائه دهنده (کلید OAuth یا API) را وصل کنید. +2. داشبورد → `Endpoints` را باز کنید و یک کلید API ایجاد کنید. +3. (اختیاری) داشبورد → `Combos` را باز کنید و زنجیره بازگشتی خود را تنظیم کنید. -### 3) Point your coding tool to OmniRoute +### 3) ابزار کدنویسی خود را روی OmniRoute قرار دهید ```txt Base URL: http://localhost:20128/v1 @@ -853,20 +853,20 @@ API Key: [copy from Endpoint page] Model: if/kimi-k2-thinking (or any provider/model prefix) ``` -### 4) Enable and validate protocols (v2.0) +### 4) فعال کردن و اعتبارسنجی پروتکل ها (v2.0) -**MCP (for tool-driven operations):** +**MCP (برای عملیات ابزار محور):** ```bash omniroute --mcp ``` -Then connect your MCP client over `stdio` and test tools like: +سپس مشتری MCP خود را به `stdio` متصل کنید و ابزارهایی مانند: - `omniroute_get_health` - `omniroute_list_combos` -**A2A (for agent-to-agent workflows):** +**A2A (برای گردش کار عامل به عامل):** ```bash curl http://localhost:20128/.well-known/agent.json @@ -878,15 +878,15 @@ curl -X POST http://localhost:20128/a2a \ -d '{"jsonrpc":"2.0","id":"quickstart","method":"message/send","params":{"skill":"quota-management","messages":[{"role":"user","content":"Give me a short quota summary."}]}}' ``` -### 5) Validate everything end-to-end (recommended) +### 5) اعتبارسنجی همه چیز از انتها به انتها (توصیه می شود) ```bash npm run test:protocols:e2e ``` -This suite validates real MCP and A2A client flows against a running app. +این مجموعه، جریان های سرویس گیرنده MCP و A2A واقعی را در برابر یک برنامه در حال اجرا تأیید می کند. -### Alternative: run from source +### جایگزین: از منبع اجرا شود ```bash cp .env.example .env @@ -897,7 +897,7 @@ PORT=20128 DASHBOARD_PORT=20129 NEXT_PUBLIC_BASE_URL=http://localhost:20129 npm
Void Linux (`xbps-src` template) -For Void Linux users, you can build a native package using `xbps-src`. Save this block as `srcpkgs/omniroute/template`: +برای کاربران Void Linux، می توانید یک بسته بومی با استفاده از `xbps-src` بسازید. این بلوک را به عنوان `srcpkgs/omniroute/template` ذخیره کنید: ```bash # Template file for 'omniroute' @@ -1005,9 +1005,9 @@ post_install() { ## 🐳 Docker -OmniRoute is available as a public Docker image on [Docker Hub](https://hub.docker.com/r/diegosouzapw/omniroute). +OmniRoute به عنوان یک تصویر عمومی Docker در [Docker Hub](https://hub.docker.com/r/diegosouzapw/omniroute) در دسترس است. -**Quick run:** +**اجرای سریع:** ```bash docker run -d \ @@ -1019,7 +1019,7 @@ docker run -d \ diegosouzapw/omniroute:latest ``` -**With environment file:** +**به همراه فایل محیطی:** ```bash # Copy and edit .env first @@ -1035,7 +1035,7 @@ docker run -d \ diegosouzapw/omniroute:latest ``` -**Using Docker Compose:** +**با استفاده از Docker نوشتن:** ```bash # Base profile (no CLI tools) @@ -1045,22 +1045,22 @@ docker compose --profile base up -d docker compose --profile cli up -d ``` -Dashboard support for Docker deployments now includes a one-click **Cloudflare Quick Tunnel** on `Dashboard → Endpoints`. The first enable downloads `cloudflared` only when needed, starts a temporary tunnel to your current `/v1` endpoint, and shows the generated `https://*.trycloudflare.com/v1` URL directly below your normal public URL. +پشتیبانی داشبورد برای استقرار Docker اکنون شامل یک **Cloudflare Quick Tunnel** با یک کلیک روی `Dashboard → Endpoints` است. اولین فعال `cloudflared` را فقط در صورت نیاز دانلود می‌کند، یک تونل موقت به نقطه پایانی فعلی `/v1` شما راه‌اندازی می‌کند و `https://*.trycloudflare.com/v1` URL تولید شده را مستقیماً زیر URL عمومی عادی شما نشان می‌دهد. Notes: -- Quick Tunnel URLs are temporary and change after every restart. -- Quick Tunnels are not auto-restored after an OmniRoute or container restart. Re-enable them from the dashboard when needed. -- Managed install currently supports Linux, macOS, and Windows on `x64` / `arm64`. -- Managed Quick Tunnels default to HTTP/2 transport to avoid noisy QUIC UDP buffer warnings in constrained container environments. Set `CLOUDFLARED_PROTOCOL=quic` or `auto` if you want a different transport. -- Docker images bundle system CA roots and pass them to managed `cloudflared`, which avoids TLS trust failures when the tunnel bootstraps inside the container. -- SQLite runs in WAL mode. `docker stop` should be allowed to finish so OmniRoute can checkpoint the latest changes back into `storage.sqlite`. -- The bundled Compose files already set a 40s stop grace period. If you run the image directly, keep `--stop-timeout 40` (or similar) so manual stops do not cut off shutdown cleanup. -- Set `CLOUDFLARED_BIN=/absolute/path/to/cloudflared` if you want OmniRoute to use an existing binary instead of downloading one. +- URL های تونل سریع موقتی هستند و پس از هر بار راه اندازی مجدد تغییر می کنند. +- تونل های سریع پس از راه اندازی مجدد OmniRoute یا کانتینر به طور خودکار بازیابی نمی شوند. در صورت نیاز دوباره آنها را از داشبورد فعال کنید. +- نصب مدیریت شده در حال حاضر از لینوکس، macOS و ویندوز در `x64` / `arm64` پشتیبانی می کند. +- تونل های سریع مدیریت شده به طور پیش فرض برای حمل و نقل HTTP/2 برای جلوگیری از هشدارهای بافر QUIC UDP پر سر و صدا در محیط های کانتینری محدود. اگر می خواهید حمل و نقل متفاوتی داشته باشید، `CLOUDFLARED_PROTOCOL=quic` یا `auto` را تنظیم کنید. +- تصاویر Docker ریشه های CA سیستم را بسته بندی می کند و آنها را به `cloudflared` مدیریت شده ارسال می کند، که از خرابی اعتماد TLS در هنگام بوت استرپ تونل در داخل ظرف جلوگیری می کند. +- SQLite در حالت WAL اجرا می شود. باید به `docker stop` اجازه داده شود تا پایان یابد تا OmniRoute بتواند آخرین تغییرات را به `storage.sqlite` بازرسی کند. +- فایل های Compose همراه از قبل یک دوره مهلت توقف 40 ثانیه تعیین کرده اند. اگر مستقیماً تصویر را اجرا می‌کنید، `--stop-timeout 40` (یا مشابه) را نگه دارید تا توقف‌های دستی پاکسازی خاموش را قطع نکنند. +- اگر می خواهید OmniRoute از یک باینری موجود به جای دانلود استفاده کند، `CLOUDFLARED_BIN=/absolute/path/to/cloudflared` را تنظیم کنید. -**Using Docker Compose with Caddy (HTTPS Auto-TLS):** +**استفاده از Docker Compose with Caddy (HTTPS Auto-TLS):** -OmniRoute can be securely exposed using Caddy's automatic SSL provisioning. Ensure your domain's DNS A record points to your server's IP. +OmniRoute را می توان با استفاده از تهیه خودکار SSL Caddy به طور ایمن در معرض دید قرار داد. مطمئن شوید که رکورد DNS A دامنه شما به IP سرور شما اشاره دارد. ```yaml services: @@ -1087,26 +1087,26 @@ volumes: omniroute-data: ``` -| Image | Tag | Size | Description | +| تصویر | برچسب | اندازه | توضیحات | | ------------------------ | -------- | ------ | --------------------- | -| `diegosouzapw/omniroute` | `latest` | ~250MB | Latest stable release | -| `diegosouzapw/omniroute` | `3.6.2` | ~250MB | Current version | +| `diegosouzapw/omniroute` | `latest` | ~250 مگابایت | آخرین نسخه پایدار | +| `diegosouzapw/omniroute` | `3.6.2` | ~250 مگابایت | نسخه فعلی | --- -## 🖥️ Desktop App — Offline & Always-On +## 🖥️ برنامه دسکتاپ — آفلاین و همیشه روشن -> 🆕 **NEW!** OmniRoute is now available as a **native desktop application** for Windows, macOS, and Linux. +> 🆕 **جدید!** OmniRoute اکنون به عنوان یک **برنامه دسکتاپ بومی** برای Windows، macOS و Linux در دسترس است. -Run OmniRoute as a standalone desktop app — no terminal, no browser, no internet required for local models. The Electron-based app includes: +OmniRoute را به عنوان یک برنامه دسکتاپ مستقل اجرا کنید - بدون پایانه، بدون مرورگر، بدون نیاز به اینترنت برای مدل‌های محلی. برنامه مبتنی بر الکترون شامل موارد زیر است: -- 🖥️ **Native Window** — Dedicated app window with system tray integration -- 🔄 **Auto-Start** — Launch OmniRoute on system login -- 🔔 **Native Notifications** — Get alerts for quota exhaustion or provider issues -- ⚡ **One-Click Install** — NSIS (Windows), DMG (macOS), AppImage (Linux) -- 🌐 **Offline Mode** — Works fully offline with bundled server +- 🖥️ **پنجره بومی** - پنجره برنامه اختصاصی با ادغام سینی سیستم +- 🔄 **شروع خودکار** — راه اندازی OmniRoute در ورود به سیستم +- 🔔 ** اعلان های بومی ** - هشدارهایی را برای اتمام سهمیه یا مشکلات ارائه دهنده دریافت کنید +- ⚡ **نصب با یک کلیک** - NSIS (ویندوز)، DMG (macOS)، AppImage (لینوکس) +- 🌐 ** حالت آفلاین ** - با سرور همراه به طور کامل آفلاین کار می کند -### Inicio Rápido +### اینیسیو راپیدو ```bash # Development mode @@ -1119,50 +1119,50 @@ npm run electron:build:mac # macOS (.dmg) — x64 & arm64 npm run electron:build:linux # Linux (.AppImage) ``` -### System Tray +### سینی سیستم -When minimized, OmniRoute lives in your system tray with quick actions: +هنگامی که به حداقل می رسد، OmniRoute با اقدامات سریع در سینی سیستم شما زندگی می کند: -- Open dashboard -- Change server port -- Quit application +- داشبورد را باز کنید +- تغییر پورت سرور +- برنامه را ترک کنید -📖 Full documentation: [`electron/README.md`](electron/README.md) +📖 مستندات کامل: [`electron/README.md`](electron/README.md) --- -## 💰 Pricing at a Glance +## 💰 قیمت در یک نگاه -| Tier | Provider | Cost | Quota Reset | Best For | +| ردیف | ارائه دهنده | هزینه | بازنشانی سهمیه | بهترین برای | | ------------------- | --------------------------- | ------------------------------------- | --------------------- | ---------------------------------- | -| **💳 SUBSCRIPTION** | Claude Code (Pro) | $20/mo | 5h + weekly | Already subscribed | -| | Codex (Plus/Pro) | $20-200/mo | 5h + weekly | OpenAI users | -| | GitHub Copilot | $10-19/mo | Monthly | GitHub users | -| **🔑 API KEY** | NVIDIA NIM | **FREE ACCESS** (current terms apply) | ~40 RPM | 70+ open models | -| | Cerebras | **FREE** (1M tok/day) | 60K TPM / 30 RPM | World's fastest | -| | Groq | **FREE** (30 RPM) | 14.4K RPD | Ultra-fast Llama/Gemma | -| | DeepSeek V3.2 | $0.27/$1.10 per 1M | None | Best price/quality reasoning | -| | xAI Grok-4 Fast | **$0.20/$0.50 per 1M** 🆕 | None | Fastest + tool calling, ultralow | -| | xAI Grok-4 (standard) | $0.20/$1.50 per 1M 🆕 | None | Reasoning flagship from xAI | -| | Mistral | Free trial + paid | Rate limited | European AI | -| | OpenRouter | Pay-per-use | None | 100+ models aggr. | -| **💰 CHEAP** | GLM-5 (via Z.AI) 🆕 | $0.5/1M | Daily 10AM | 128K output, newest flagship | -| | GLM-4.7 | $0.6/1M | Daily 10AM | Budget backup | -| | MiniMax M2.5 🆕 | $0.3/1M input | 5-hour rolling | Reasoning + agentic tasks | -| | MiniMax M2.1 | $0.2/1M | 5-hour rolling | Cheapest option | -| | Kimi K2.5 (Moonshot API) 🆕 | Pay-per-use | None | Direct Moonshot API access | -| | Kimi K2 | $9/mo flat | 10M tokens/mo | Predictable cost | -| **🆓 FREE ACCESS** | Qoder | **$0** | Limits apply | Selected models; terms apply | -| | Qwen | **$0** | Limits apply | Selected models; terms apply | -| | Kiro | **$0** | Credit/account limits | Claude access; current terms apply | -| | LongCat signup credit | **$0** (10M one-time; KYC) | One-time | Signup grant; not recurring | -| | Pollinations AI 🆕 | **$0** (no key needed) | 1 req/15s | GPT-5, Claude, DeepSeek, Llama 4 | -| | Cloudflare Workers AI 🆕 | **$0** (10K Neurons/day) | ~150 resp/day | 50+ models, global edge | -| | Scaleway AI 🆕 | **$0** (1M tokens total) | Rate limited | EU/GDPR, Qwen3 235B, Llama 70B | +| **💳 اشتراک ** | کد Claude (Pro) | 20 دلار در ماه | 5 ساعت + هفتگی | قبلاً مشترک شده است | +| | Codex (Plus/Pro) | 20-200 دلار در ماه | 5 ساعت + هفتگی | کاربران OpenAI | +| | GitHub Copilot | 10-19 دلار در ماه | ماهانه | کاربران GitHub | +| **🔑 کلید API ** | NVIDIA NIM | **دسترسی رایگان** (شرایط فعلی اعمال می شود) | ~40 دور در دقیقه | 70+ مدل باز | +| | Cerebras | **رایگان** (1 میلیون توک در روز) | 60K TPM / 30 RPM | سریعترین جهان | +| | Groq | **رایگان** (30 دور در دقیقه) | 14.4K RPD | Llama/Gemma فوق العاده سریع | +| | DeepSeek V3.2 | 0.27 دلار / 1.10 دلار در هر 1 میلیون | هیچکدام | بهترین استدلال قیمت/کیفیت | +| | xAI Grok-4 Fast | **0.20$/0.50$ در هر 1 میلیون** 🆕 | هیچکدام | سریعترین + فراخوانی ابزار، فوق العاده کم | +| | xAI Grok-4 (استاندارد) | 0.20 دلار / 1.50 دلار به ازای هر 1 میلیون 🆕 | هیچکدام | گل سرسبد استدلال از xAI | +| | میسترال | آزمایشی رایگان + پولی | نرخ محدود | هوش مصنوعی اروپایی | +| | OpenRouter | پرداخت به ازای استفاده | هیچکدام | 100+ مدل aggr. | +| **💰 ارزان ** | GLM-5 (از طریق Z.AI) 🆕 | 0.5/1 میلیون دلار | روزانه 10 صبح | خروجی 128K، جدیدترین پرچمدار | +| | GLM-4.7 | 0.6/1 میلیون دلار | روزانه 10 صبح | پشتیبان بودجه | +| | MiniMax M2.5 🆕 | 0.3/1 میلیون دلار ورودی | نورد 5 ساعته | استدلال + وظایف نمایندگی | +| | MiniMax M2.1 | 0.2/1 میلیون دلار | نورد 5 ساعته | ارزان ترین گزینه | +| | Kimi K2.5 (Moonshot API) 🆕 | پرداخت به ازای استفاده | هیچکدام | دسترسی مستقیم Moonshot API | +| | Kimi K2 | 9 دلار در ماه آپارتمان | 10 میلیون توکن در ماه | هزینه قابل پیش بینی | +| **🆓 دسترسی رایگان ** | Qoder | **0$** | محدودیت اعمال می شود | مدل های منتخب؛ شرایط اعمال می شود | +| | Qwen | **0$** | محدودیت اعمال می شود | مدل های منتخب؛ شرایط اعمال می شود | +| | Kiro | **0$** | محدودیت اعتبار/حساب | دسترسی Claude؛ شرایط فعلی اعمال می شود | +| | اعتبار ثبت نام LongCat | **0$** (10 میلیون یکبار مصرف؛ KYC) | یکبار مصرف | کمک هزینه ثبت نام؛ تکرار نشدن | +| | Pollinations AI 🆕 | **0$** (بدون نیاز به کلید) | 1 req/15s | GPT-5، Claude، DeepSeek، Llama 4 | +| | Cloudflare Workers AI 🆕 | **0$** (10 هزار نورون در روز) | ~150 بار در روز | 50+ مدل، لبه جهانی | +| | Scaleway AI 🆕 | **0$** (مجموع 1 میلیون توکن) | نرخ محدود | EU/GDPR، Qwen3 235B، Llama 70B | -> 🆕 **New models added (Mar 2026):** Grok-4 Fast family at $0.20/$0.50/M (benchmarked at 1143ms — 30% faster than Gemini 2.5 Flash), GLM-5 via Z.AI with 128K output, MiniMax M2.5 reasoning, DeepSeek V3.2 updated pricing, Kimi K2.5 via Moonshot direct API. +> 🆕 **مدل‌های جدید اضافه شده (مارس 2026):** خانواده Grok-4 Fast با 0.20 دلار/0.50 دلار در میلیون دلار (معیار شده در 1143 میلی‌ثانیه — 30 درصد سریع‌تر از فلش Gemini 2.5)، GLM-5 از طریق Z.AI، خروجی Z.AI، Z.AI، Z. DeepSeek V3.2 قیمت به روز شده، Kimi K2.5 از طریق Moonshot مستقیم API. -**💡 $0 Combo Stack — The Complete Free Setup:** +**💡 $0 Combo Stack — راه اندازی کامل رایگان:** ``` # 🆓 Free-access examples — provider limits and terms apply @@ -1179,138 +1179,138 @@ NVIDIA NIM (nvidia/) → selected models — current rate limits apply Cerebras (cerebras/) → Llama/Qwen world-fastest — 1M tok/day ``` -**Current $0 access where listed; availability is not guaranteed.** A combo can try the next eligible route when a quota or upstream fails. +**دسترسی کنونی $0 در جایی که فهرست شده است. در دسترس بودن تضمین نشده است.** یک ترکیبی می‌تواند مسیر واجد شرایط بعدی را در صورت شکست سهمیه یا بالادستی امتحان کند. --- --- -## 🆓 Free Models — What You Actually Get +## 🆓 مدل های رایگان - آنچه در واقع به دست می آورید -> The entries below summarize access that was listed as free when audited. Provider quotas, card/account/KYC requirements, models, regions and terms can change. A combo broadens fallback coverage but does not guarantee uninterrupted $0 access. +> ورودی‌های زیر دسترسی‌هایی را که هنگام ممیزی رایگان فهرست شده‌اند، خلاصه می‌کنند. سهمیه‌های ارائه‌دهنده، کارت/حساب/ الزامات KYC، مدل‌ها، مناطق و شرایط می‌توانند تغییر کنند. ترکیبی پوشش بازگشتی را گسترش می دهد اما دسترسی بدون وقفه $0 را تضمین نمی کند. -### 🔵 CLAUDE MODELS (via Kiro — AWS Builder ID) +### 🔵 CLAUDE MODELS (از طریق Kiro — AWS Builder ID) -| Model | Prefix | Limit | Rate Limit | +| مدل | پیشوند | محدود | محدودیت نرخ | | ------------------- | ------ | ------------- | --------------------- | -| `claude-sonnet-4.5` | `kr/` | No published token cap | Provider/account limits may apply | -| `claude-haiku-4.5` | `kr/` | No published token cap | Provider/account limits may apply | -| `claude-opus-4.6` | `kr/` | No published token cap | Latest Opus; provider/account limits apply | +| `claude-sonnet-4.5` | `kr/` | بدون درپوش توکن منتشر شده | ممکن است محدودیت های ارائه دهنده/حساب اعمال شود | +| `claude-haiku-4.5` | `kr/` | بدون درپوش توکن منتشر شده | ممکن است محدودیت های ارائه دهنده/حساب اعمال شود | +| `claude-opus-4.6` | `kr/` | بدون درپوش توکن منتشر شده | آخرین Opus; محدودیت های ارائه دهنده/حساب اعمال می شود | -### 🟢 QODER MODELS (Free PAT via qodercli) +### مدل QODER (رایگان PAT از طریق qodercli) -| Model | Prefix | Limit | Rate Limit | +| مدل | پیشوند | محدود | محدودیت نرخ | | ------------------ | ------ | ------------- | --------------- | -| `kimi-k2-thinking` | `if/` | No published token cap | Provider/account limits may apply | -| `qwen3-coder-plus` | `if/` | No published token cap | Provider/account limits may apply | -| `deepseek-r1` | `if/` | No published token cap | Provider/account limits may apply | -| `minimax-m2.1` | `if/` | No published token cap | Provider/account limits may apply | -| `kimi-k2` | `if/` | No published token cap | Provider/account limits may apply | +| `kimi-k2-thinking` | `if/` | بدون درپوش توکن منتشر شده | ممکن است محدودیت های ارائه دهنده/حساب اعمال شود | +| `qwen3-coder-plus` | `if/` | بدون درپوش توکن منتشر شده | ممکن است محدودیت های ارائه دهنده/حساب اعمال شود | +| `deepseek-r1` | `if/` | بدون درپوش توکن منتشر شده | ممکن است محدودیت های ارائه دهنده/حساب اعمال شود | +| `minimax-m2.1` | `if/` | بدون درپوش توکن منتشر شده | ممکن است محدودیت های ارائه دهنده/حساب اعمال شود | +| `kimi-k2` | `if/` | بدون درپوش توکن منتشر شده | ممکن است محدودیت های ارائه دهنده/حساب اعمال شود | -> Recommended connection method: **Personal Access Token + `qodercli`**. Browser OAuth is -> experimental and disabled by default unless `QODER_OAUTH_*` environment variables are configured. +> روش اتصال پیشنهادی: ** رمز دسترسی شخصی + `qodercli`**. مرورگر OAuth است +> آزمایشی و به طور پیش فرض غیرفعال است مگر اینکه متغیرهای محیطی `QODER_OAUTH_*` پیکربندی شده باشند. -### 🟡 QWEN MODELS (Device Code Auth) +### 🡑 مدل‌های QWEN (تأیید کد دستگاه) -| Model | Prefix | Limit | Rate Limit | +| مدل | پیشوند | محدود | محدودیت نرخ | | ------------------- | ------ | ------------- | ------------------- | -| `qwen3-coder-plus` | `qw/` | No published token cap | Provider/account limits may apply | -| `qwen3-coder-flash` | `qw/` | No published token cap | Provider/account limits may apply | -| `qwen3-coder-next` | `qw/` | No published token cap | Provider/account limits may apply | -| `vision-model` | `qw/` | No published token cap | Multimodal; provider/account limits may apply | +| `qwen3-coder-plus` | `qw/` | بدون درپوش توکن منتشر شده | ممکن است محدودیت های ارائه دهنده/حساب اعمال شود | +| `qwen3-coder-flash` | `qw/` | بدون درپوش توکن منتشر شده | ممکن است محدودیت های ارائه دهنده/حساب اعمال شود | +| `qwen3-coder-next` | `qw/` | بدون درپوش توکن منتشر شده | ممکن است محدودیت های ارائه دهنده/حساب اعمال شود | +| `vision-model` | `qw/` | بدون درپوش توکن منتشر شده | چند وجهی؛ ممکن است محدودیت های ارائه دهنده/حساب اعمال شود | -### ⚫ NVIDIA NIM (Free API Key — build.nvidia.com) +### ⚫ NVIDIA NIM (کلید رایگان API — build.nvidia.com) -| Tier | Daily Limit | Rate Limit | Notes | +| ردیف | محدودیت روزانه | محدودیت نرخ | یادداشت ها | | ---------- | ------------ | ----------- | ------------------------------------------------------ | -| Free (Dev) | No token cap | **~40 RPM** | 70+ models; transitioning to pure rate limits mid-2025 | +| رایگان (Dev) | بدون درپوش رمزی | **~40 دور در دقیقه** | 70+ مدل؛ انتقال به محدودیت های نرخ خالص اواسط سال 2025 | -Popular free models: `moonshotai/kimi-k2.5` (Kimi K2.5), `z-ai/glm4.7` (GLM 4.7), `deepseek-ai/deepseek-v3.2` (DeepSeek V3.2), `nvidia/llama-3.3-70b-instruct`, `deepseek/deepseek-r1` +مدل‌های رایگان پرطرفدار: `moonshotai/kimi-k2.5` (Kimi K2.5)، `z-ai/glm4.7` (GLM 4.7)، `deepseek-ai/deepseek-v3.2` (DeepSeek V3.2)، KimiTXQ3. -### ⚪ CEREBRAS (Free API Key — inference.cerebras.ai) +### ⚪ CEREBRAS (کلید رایگان API — inference.cerebras.ai) -| Tier | Daily Limit | Rate Limit | Notes | +| ردیف | محدودیت روزانه | محدودیت نرخ | یادداشت ها | | ---- | ----------------- | ---------------- | ------------------------------------------- | -| Free | **1M tokens/day** | 60K TPM / 30 RPM | World's fastest LLM inference; resets daily | +| رایگان | **1 میلیون توکن در روز** | 60K TPM / 30 RPM | سریعترین استنتاج LLM در جهان. تنظیم مجدد روزانه | -Available free: `llama-3.3-70b`, `llama-3.1-8b`, `deepseek-r1-distill-llama-70b` +رایگان موجود: `llama-3.3-70b`، `llama-3.1-8b`، `deepseek-r1-distill-llama-70b` -### 🔴 GROQ (Free API Key — console.groq.com) +### 🔴 GROQ (کلید رایگان API — console.groq.com) -| Tier | Daily Limit | Rate Limit | Notes | +| ردیف | محدودیت روزانه | محدودیت نرخ | یادداشت ها | | ---- | ------------- | ---------------- | ----------------------------------------- | -| Free | **14.4K RPD** | 30 RPM per model | No credit card; 429 on limit, not charged | +| رایگان | **14.4K RPD** | 30 دور در دقیقه در هر مدل | بدون کارت اعتباری؛ 429 محدود، شارژ نشده | -Available free: `llama-3.3-70b-versatile`, `gemma2-9b-it`, `mixtral-8x7b`, `whisper-large-v3` +رایگان موجود: `llama-3.3-70b-versatile`، `gemma2-9b-it`، `mixtral-8x7b`، `whisper-large-v3` -### 🔴 LONGCAT AI (Signup credit — KYC required) +### 🔴 LONGCAT AI (اعتبار ثبت نام — KYC مورد نیاز است) -| Model | Prefix | Current catalog grant | Notes | +| مدل | پیشوند | کمک هزینه کاتالوگ فعلی | یادداشت ها | | ------------- | ------ | ----------------------- | --------------------------------------------------- | -| `LongCat-2.0` | `lc/` | **10M tokens one-time** | Signup grant; not a recurring monthly or daily pool | +| `LongCat-2.0` | `lc/` | **10 میلیون توکن یکبار مصرف** | کمک هزینه ثبت نام؛ نه یک استخر تکراری ماهانه یا روزانه | -> Provider terms, eligibility and model availability can change. See [`FREE_TIERS.md`](../../reference/FREE_TIERS.md) for the audited catalog entry. +> شرایط ارائه دهنده، واجد شرایط بودن و در دسترس بودن مدل می تواند تغییر کند. [`FREE_TIERS.md`](../../reference/FREE_TIERS.md) را برای ورودی کاتالوگ ممیزی شده ببینید. -### 🟢 POLLINATIONS AI (No API Key Required) 🆕 +### AI POLLINATIONS (بدون نیاز به کلید API) 🆕 -| Model | Prefix | Rate Limit | Provider Behind | +| مدل | پیشوند | محدودیت نرخ | ارائه دهنده پشت | | ---------- | ------ | ---------- | ------------------ | -| `openai` | `pol/` | 1 req/15s | GPT-5 | -| `claude` | `pol/` | 1 req/15s | Anthropic Claude | -| `gemini` | `pol/` | 1 req/15s | Google Gemini | -| `deepseek` | `pol/` | 1 req/15s | DeepSeek V3 | -| `llama` | `pol/` | 1 req/15s | Meta Llama 4 Scout | -| `mistral` | `pol/` | 1 req/15s | Mistral AI | +| `openai` | `pol/` | 1 req/15s | GPT-5 | +| `claude` | `pol/` | 1 req/15s | آنتروپیک Claude | +| `gemini` | `pol/` | 1 req/15s | گوگل جمینی | +| `deepseek` | `pol/` | 1 req/15s | DeepSeek V3 | +| `llama` | `pol/` | 1 req/15s | Meta Llama 4 Scout | +| `mistral` | `pol/` | 1 req/15s | Mistral AI | -> ✨ **Zero friction:** No signup, no API key. Add the Pollinations provider with an empty key field and it works immediately. +> ✨ **اصطکاک صفر:** بدون ثبت نام، بدون کلید API. ارائه دهنده Pollinations را با یک فیلد کلید خالی اضافه کنید و بلافاصله کار می کند. -### 🟠 CLOUDFLARE WORKERS AI (Free API Key — cloudflare.com) 🆕 +### CLOUDFLARE WORKERS AI (کلید رایگان API — cloudflare.com) 🆕 -| Tier | Daily Neurons | Equivalent Usage | Notes | +| ردیف | نورون های روزانه | استفاده معادل | یادداشت ها | | ---- | ------------- | --------------------------------------- | ----------------------- | -| Free | **10,000** | ~150 LLM resp / 500s audio / 15K embeds | Global edge, 50+ models | +| رایگان | **10000** | ~150 LLM resp / صدای 500s / 15K جاسازی | لبه جهانی، 50+ مدل | -Popular free models: `@cf/meta/llama-3.3-70b-instruct`, `@cf/google/gemma-3-12b-it`, `@cf/openai/whisper-large-v3-turbo` (free audio!), `@cf/qwen/qwen2.5-coder-15b-instruct` +مدل های رایگان محبوب: `@cf/meta/llama-3.3-70b-instruct`، `@cf/google/gemma-3-12b-it`، `@cf/openai/whisper-large-v3-turbo` (صدای رایگان!)، `@cf/qwen/qwen2.5-coder-15b-instruct` -> Requires API Token + Account ID from [dash.cloudflare.com](https://dash.cloudflare.com). Store Account ID in provider settings. +> به رمز API + شناسه حساب از [dash.cloudflare.com](https://dash.cloudflare.com) نیاز دارد. شناسه حساب را در تنظیمات ارائه دهنده ذخیره کنید. -### 🟣 SCALEWAY AI (1M Free Tokens — scaleway.com) 🆕 +### SCALEWAY AI (1 میلیون توکن رایگان — scaleway.com) 🆕 -| Tier | Free Quota | Location | Notes | +| ردیف | سهمیه آزاد | مکان | یادداشت ها | | ---- | ------------- | ------------ | ----------------------------------- | -| Free | **1M tokens** | 🇫🇷 Paris, EU | No credit card needed within limits | +| رایگان | **1 میلیون توکن** | 🇫🇷 پاریس، اتحادیه اروپا | بدون نیاز به کارت اعتباری در محدوده | -Available free: `qwen3-235b-a22b-instruct-2507` (Qwen3 235B!), `llama-3.1-70b-instruct`, `mistral-small-3.2-24b-instruct-2506`, `deepseek-v3-0324` +رایگان موجود: `qwen3-235b-a22b-instruct-2507` (Qwen3 235B!)، `llama-3.1-70b-instruct`، `mistral-small-3.2-24b-instruct-2506`، `deepseek-v3-0324` -> EU/GDPR compliant. Get API key at [console.scaleway.com](https://console.scaleway.com). +> مطابق با اتحادیه اروپا/GDPR. کلید API را در [console.scaleway.com](https://console.scaleway.com) دریافت کنید. -> **💡 Free-access examples (provider limits and terms apply):** +> **💡 نمونه های دسترسی رایگان (محدودیت ها و شرایط ارائه دهنده اعمال می شود):** > > ``` -> Kiro (kr/) → Claude access — account/credit limits apply -> Qoder (if/) → selected models — no published token cap; limits apply -> LongCat (lc/) → LongCat-2.0 — 10M one-time signup credit; KYC required -> Pollinations (pol/) → GPT-5, Claude, DeepSeek, Llama 4 — no key needed -> Qwen (qw/) → selected models — no published token cap; limits apply -> Gemini (gemini/) → selected free-tier models — current quotas apply -> Cloudflare AI (cf/) → 50+ models — 10K Neurons/day -> Scaleway (scw/) → Qwen3 235B, Llama 70B — 1M free tokens (EU) -> Groq (groq/) → selected models — current per-model rate limits apply -> NVIDIA NIM (nvidia/) → selected models — current rate limits apply -> Cerebras (cerebras/) → Llama/Qwen world-fastest — 1M tok/day +> Kiro (kr/) → دسترسی Claude — محدودیت های حساب/اعتبار اعمال می شود +> Qoder (اگر/) ← مدل های انتخابی — بدون پوشش توکن منتشر شده. محدودیت اعمال می شود +> LongCat (lc/) → LongCat-2.0 — 10 میلیون اعتبار ثبت نام یکباره؛ KYC مورد نیاز است +> Pollinations (pol/) → GPT-5، Claude، DeepSeek، Llama 4 — بدون نیاز به کلید +> Qwen (qw/) ← مدل‌های انتخابی — بدون درپوش توکن منتشر شده. محدودیت اعمال می شود +> جمینی (جمینی/) ← مدل های سطح آزاد انتخاب شده — سهمیه های فعلی اعمال می شود +> Cloudflare AI (cf/) → بیش از 50 مدل — 10 هزار نورون در روز +> Scaleway (scw/) → Qwen3 235B، Llama 70B — 1 میلیون توکن رایگان (EU) +> Groq (groq/) ← مدل‌های انتخابی - محدودیت‌های نرخ فعلی برای هر مدل اعمال می‌شود +> NVIDIA NIM (nvidia/) → مدل های انتخابی — محدودیت های نرخ فعلی اعمال می شود +> Cerebras (مغز/) → لاما/Qwen سریعترین جهان — 1 میلیون توک در روز > ``` -## 🎙️ Free Transcription Combo +## 🎙️ ترکیب رونویسی رایگان -> Transcription access depends on each upstream allowance — Deepgram and AssemblyAI signup credits can lead, with Groq Whisper as a rate-limited fallback. +> دسترسی به رونویسی به هر کمک هزینه بالادستی بستگی دارد - اعتبارات ثبت نام Deepgram و AssemblyAI می توانند منجر شوند، با Groq Whisper به عنوان یک بازگشت با نرخ محدود. -| Provider | Free Credits | Best Model | Rate Limit | +| ارائه دهنده | اعتبار رایگان | بهترین مدل | محدودیت نرخ | | ----------------- | --------------------------- | -------------------------------------------- | ---------------------------------------- | -| 🟢 **Deepgram** | **$200 free** (signup) | `nova-3` — best accuracy, 30+ languages | No RPM limit on free credits | -| 🔵 **AssemblyAI** | **$50 free** (signup) | `universal-3-pro` — chapters, sentiment, PII | No RPM limit on free credits | -| 🔴 **Groq** | **Free tier; limits apply** | `whisper-large-v3` — OpenAI Whisper | Current model-specific rate limits apply | +| 🢢 **دیپگرام** | **200 دلار رایگان** (ثبت نام) | `nova-3` — بهترین دقت، بیش از 30 زبان | بدون محدودیت RPM در اعتبارات رایگان | +| 🔵 **AssemblyAI** | **50 دلار رایگان ** (ثبت نام) | `universal-3-pro` — فصول، احساسات، PII | بدون محدودیت RPM در اعتبارات رایگان | +| 🔴 **Groq** | ** ردیف آزاد؛ محدودیت اعمال می شود** | `whisper-large-v3` — OpenAI Whisper | محدودیت‌های نرخ ویژه مدل فعلی اعمال می‌شود | -**Suggested combo in `/dashboard/combos`:** +** ترکیب پیشنهادی در `/dashboard/combos`:** ``` Name: free-transcription @@ -1321,180 +1321,180 @@ Nodes: [3] groq/whisper-large-v3 → free access; rate limits apply ``` -Then in `/dashboard/media` → **Transcription** tab: upload any audio or video file → select your combo endpoint → get transcription in supported formats. +سپس در زبانه `/dashboard/media` → **رونویسی**: هر فایل صوتی یا تصویری را آپلود کنید → نقطه پایانی ترکیبی خود را انتخاب کنید → رونویسی را در قالب های پشتیبانی شده دریافت کنید. -## 💡 Key Features +## 💡 ویژگی های کلیدی -OmniRoute v3.6 is built as an operational platform, not just a relay proxy. +OmniRoute v3.6 به عنوان یک پلت فرم عملیاتی ساخته شده است، نه فقط یک پروکسی رله. -### 🆕 New — v3.6.x Highlights (Apr 2026) +### 🆕 جدید — نسخه های برجسته نسخه 3.6.x (آوریل 2026) -| Feature | What It Does | +| ویژگی | چه می کند | | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -| 🌐 **V1 WebSocket Bridge** | OpenAI-compatible WebSocket traffic upgraded and proxied via `/v1/ws` — full streaming over WS with session auth (API key or session cookie) | -| 🔑 **Sync Tokens & Config Bundle** | Issue/revoke sync tokens for config sync endpoints. Config bundles versioned with ETag for bandwidth-efficient polling | -| 🧠 **GLM Thinking (glmt) Preset** | GLM Thinking registered first-class: 65 536 max tokens, 24 576 thinking budget, 900s timeout, usage sync & pricing — Claude-compatible API | -| 🔢 **Hybrid Token Counting** | Uses provider-side `/messages/count_tokens` when available; falls back to estimation — accurate usage tracking without guessing | -| 🌱 **Model Alias Auto-Seed** | 30+ cross-proxy dialect aliases normalised at startup — no more routing mismatches | -| 🛡️ **Safe Outbound Fetch** | All provider validation and model discovery go through a guarded fetch layer blocking private/local URLs with retry, timeout, and SSRF protection | -| ⏳ **Wait For Cooldown** | Server-side chat retries when every candidate connection is cooling down; configurable `enabled`, `maxRetries`, and `maxRetryWaitSec` | -| 🔍 **Runtime Env Validation** | Startup validates all env vars with Zod schemas — clear errors for missing secrets, invalid URLs, or wrong types | -| 📋 **Compliance Audit Expansion** | Structured audit logs with pagination, request context, auth events, provider CRUD events, and SSRF-blocked validation logging | -| 🔐 **TPS Log Metric** | Log details modal shows Tokens Per Second (TPS) — quick performance at-a-glance for every request | -| 🗑️ **Uninstall / Full Uninstall** | `npm run uninstall` keeps data, `npm run uninstall:full` removes everything — clean removal for all install methods | -| 🔧 **OAuth Env Repair** | One-click "Repair env" action for OAuth providers restores missing env vars and fixes broken auth state | -| 🔒 **Graceful Electron Shutdown** | Electron `before-quit` shuts down Next.js gracefully, preventing SQLite WAL database locks on desktop close | -| 👁️ **Model Visibility Toggle** | Per-model visibility toggle (👁 icon) with search filter and active-count badge (`N/M active`) on provider pages | -| 📧 **Email Privacy Masking** | OAuth account emails masked (`di*****@g****.com`), full address visible on hover | -| 🔗 **Context Relay Strategy** | Combo strategy preserving session continuity via structured handoff summaries when accounts rotate mid-conversation | -| 🛡️ **Proxy Hardening** | Token health check, API key validation, and undici dispatcher all honor proxy config | -| ⚠️ **Node.js 24 Login Warning** | Login page proactively detects incompatible Node.js versions and shows a clear warning banner | -| 📎 **Gemini PDF Attachments** | PDF attachments correctly routed to Gemini via `inline_data` and generic base64 detection | -| 🔒 **CodeQL Security Hardening** | Resolved SSRF, insecure randomness, polynomial ReDoS, and incomplete URL sanitization alerts | +| 🌐 ** پل V1 WebSocket ** | ترافیک OpenAI سازگار با WebSocket ارتقا یافته و از طریق `/v1/ws` پروکسی شده است — پخش جریانی کامل از طریق WS با تأیید جلسه (کلید API یا کوکی جلسه) | +| 🔑 **همگام سازی نشانه ها و بسته پیکربندی** | برای نقاط پایانی همگام سازی پیکربندی، نشانه های همگام سازی را صادر/لغو کنید. بسته‌های پیکربندی با ETag برای نظرسنجی با پهنای باند کارآمد نسخه‌بندی شده‌اند | +| 🧠 **GLM از پیش تنظیم تفکر (glmt)** | GLM Thinking ثبت شده درجه یک: 65 536 حداکثر توکن، 24 576 بودجه فکری، مهلت زمانی 900s، همگام سازی استفاده و قیمت گذاری — Claude سازگار API | +| 🔢 **شمارش توکن هیبریدی** | در صورت موجود بودن از `/messages/count_tokens` سمت ارائه دهنده استفاده می کند. بازگشت به تخمین - ردیابی دقیق استفاده بدون حدس زدن | +| 🌱 **مدل مستعار خودکار بذر ** | بیش از 30 نام مستعار گویش متقابل پروکسی در هنگام راه‌اندازی عادی شدند — دیگر عدم تطابق مسیریابی | +| 🛡️ **واکشی ایمن خروجی** | تمام اعتبار سنجی ارائه دهنده و کشف مدل از طریق یک لایه واکشی محافظت شده انجام می شود که URL های خصوصی/محلی را با تلاش مجدد، مهلت زمانی و حفاظت SSRF مسدود می کند | +| ⏳ **منتظر خنک شدن باشید** | هنگامی که هر اتصال نامزد در حال خنک شدن است، چت سمت سرور دوباره تکرار می شود. قابل تنظیم `enabled`، `maxRetries`، و `maxRetryWaitSec` | +| 🔍 **Runtime Env Validation** | راه‌اندازی تمام env vars را با طرحواره‌های Zod تأیید می‌کند - خطاهای پاک برای اسرار گم‌شده، URL‌های نامعتبر یا انواع اشتباه | +| 📋 **توسعه حسابرسی انطباق** | گزارش‌های حسابرسی ساختاریافته با صفحه‌بندی، زمینه درخواست، رویدادهای احراز هویت، رویدادهای CRUD ارائه‌دهنده، و ثبت اعتبارسنجی مسدود شده با SSRF | +| 🔐 **TPS Log Metric** | جزئیات گزارش مودال نشان می دهد نشانه ها در هر ثانیه (TPS) — عملکرد سریع در یک نگاه برای هر درخواست | +| 🗑️ **حذف نصب / حذف کامل ** | `npm run uninstall` داده ها را نگه می دارد، `npm run uninstall:full` همه چیز را حذف می کند — حذف تمیز برای همه روش های نصب | +| 🔧 **OAuth Env Repair** | اقدام "Repair env" با یک کلیک برای ارائه دهندگان OAuth، vars env گم شده را بازیابی می کند و وضعیت احراز هویت شکسته را رفع می کند | +| 🔒 **خاموشی برازنده الکترون** | Electron `before-quit` Next.js را با زیبایی خاموش می کند و از قفل شدن پایگاه داده SQLite WAL در دسکتاپ جلوگیری می کند | +| 👁️ **تغییر قابلیت مشاهده مدل** | جابجایی نمای هر مدل (نماد 👁) با فیلتر جستجو و نشان شمارش فعال (`N/M active`) در صفحات ارائه دهنده | +| 📧 **پوشش حریم خصوصی ایمیل** | ایمیل های حساب OAuth پوشانده شده است (`di*****@g****.com`)، آدرس کامل قابل مشاهده در شناور | +| 🔗 **استراتژی رله زمینه** | استراتژی ترکیبی حفظ تداوم جلسه از طریق خلاصه‌های دستیابی ساختاریافته هنگامی که حساب‌ها در میانه مکالمه می‌چرخند | +| 🛡️ **سخت شدن پروکسی** | بررسی سلامت توکن، اعتبار سنجی کلید API و undici dispatcher تمام پیکربندی پروکسی افتخاری | +| ⚠️ **اخطار ورود به سیستم Node.js 24** | صفحه ورود به طور فعال نسخه های ناسازگار Node.js را شناسایی می کند و یک بنر هشدار واضح را نشان می دهد | +| 📎 **ضمیمه های PDF Gemini** | پیوست‌های پی‌دی‌اف به‌درستی به Gemini از طریق `inline_data` و تشخیص عمومی base64 هدایت شدند | +| 🔒 **CodeQL Security Hardening** | SSRF حل‌شده، تصادفی ناامن، چندجمله‌ای ReDoS و هشدارهای بهداشتی ناقص URL | -### 🆕 New — ClawRouter-Inspired Improvements (Mar 2026) +### 🆕 جدید - بهبودهای الهام گرفته از ClawRouter (مارس 2026) -| Feature | What It Does | +| ویژگی | چه می کند | | ------------------------------------ | ------------------------------------------------------------------------------------------- | -| ⚡ **Grok-4 Fast Family** | xAI models at $0.20/$0.50/M — benchmarked 1143ms (30% faster than Gemini 2.5 Flash) | -| 🧠 **GLM-5 via Z.AI** | 128K output context, $0.5/1M — newest flagship from the GLM family | -| 🔮 **MiniMax M2.5** | Reasoning + agentic tasks at $0.30/1M — significant upgrade from M2.1 | -| 🎯 **toolCalling Flag per Model** | Per-model `toolCalling: true/false` in registry — AutoCombo skips non-tool-capable models | -| 🌍 **Multilingual Intent Detection** | PT/ZH/ES/AR keywords in AutoCombo scoring — better model selection for non-English content | -| 📊 **Benchmark-Driven Fallbacks** | Real p95 latency from live requests feeds combo scoring — AutoCombo learns from actual data | -| 🔁 **Request Deduplication** | Content-hash based dedup window — multi-agent safe, prevents duplicate charges | -| 🔌 **Pluggable RouterStrategy** | Extensible `RouterStrategy` interface — add custom routing logic as plugins | +| ⚡ **Grok-4 Fast Family** | مدل‌های xAI با قیمت 0.20 دلار / 0.50 دلار در میلیون - 1143 میلی‌ثانیه (30 درصد سریع‌تر از فلش Gemini 2.5) محک‌گذاری شده | +| 🧠 **GLM-5 از طریق Z.AI** | زمینه خروجی 128 هزار دلاری، 0.5/1 میلیون دلار — جدیدترین پرچمدار خانواده GLM | +| 🔮 **MiniMax M2.5** | استدلال + وظایف نمایندگی با 0.30 دلار / 1 میلیون دلار - ارتقاء قابل توجه از M2.1 | +| 🎯 **ابزار Calling Flag در هر مدل** | هر مدل `toolCalling: true/false` در رجیستری — AutoCombo مدل‌های غیرقابل ابزار را حذف می‌کند | +| 🌍 **تشخیص قصد چند زبانه** | کلمات کلیدی PT/ZH/ES/AR در امتیازدهی AutoCombo — انتخاب مدل بهتر برای محتوای غیر انگلیسی | +| 📊 **معیارهای بازگشتی** | تأخیر واقعی p95 از درخواست‌های زنده امتیازدهی ترکیبی — AutoCombo از داده‌های واقعی یاد می‌گیرد | +| 🔁 **درخواست حذف مجدد ** | پنجره dedup مبتنی بر هش محتوا — ایمن چند عاملی، از هزینه های تکراری جلوگیری می کند | +| 🔌 **استراتژی روتر قابل اتصال** | رابط توسعه پذیر `RouterStrategy` — اضافه کردن منطق مسیریابی سفارشی به عنوان پلاگین | -### 🚀 Previous v2.0.9+ — Playground, CLI Fingerprints & ACP +### 🚀 قبلی نسخه 2.0.9+ — زمین بازی، اثر انگشت CLI و ACP -| Feature | What It Does | +| ویژگی | چه می کند | | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 🎮 **Model Playground** | Dashboard page to test any model directly — provider/model/endpoint selectors, Monaco Editor, streaming, abort, timing | -| 🔏 **CLI Fingerprint Matching** | Per-provider header/body ordering to match native CLI signatures — toggle per provider in Settings > Security. **Your proxy IP is preserved** | -| 🤖 **ACP Agents Dashboard** | Debug › Agents page — grid of 14 agents with install status, version, custom agent form for any CLI tool. **OpenCode** users get a "Download opencode.json" button that auto-generates a ready-to-use config with all available models. | -| 🔧 **Custom Model `apiFormat` Routing** | Custom models with `apiFormat: "responses"` now correctly route to the Responses API translator | -| 🏢 **Codex Workspace Isolation** | Multiple Codex workspaces per email — OAuth correctly separates connections by workspace ID | -| 🔄 **Electron Auto-Update** | Desktop app checks for updates + auto-install on restart | +| 🎮 **مدل زمین بازی** | صفحه داشبورد برای آزمایش مستقیم هر مدل — ارائه دهنده/مدل/انتخاب کننده نقطه پایانی، ویرایشگر موناکو، پخش جریانی، لغو، زمان بندی | +| 🔏 **تطابق اثر انگشت CLI** | سفارش سرصفحه/بدنه هر ارائه دهنده برای مطابقت با امضاهای بومی CLI — در تنظیمات > امنیت، هر ارائه دهنده را تغییر دهید. **IP پروکسی شما حفظ می شود** | +| 🤖 **داشبورد نمایندگان ACP** | اشکال زدایی › صفحه نمایندگان - شبکه ای از 14 عامل با وضعیت نصب، نسخه، فرم عامل سفارشی برای هر ابزار CLI. **کاربران OpenCode** دکمه "دانلود opencode.json" را دریافت می کنند که به طور خودکار یک پیکربندی آماده برای استفاده را با همه مدل های موجود ایجاد می کند. | +| 🔧 **مدل سفارشی `apiFormat` مسیریابی** | مدل‌های سفارشی با `apiFormat: "responses"` اکنون به درستی به مترجم Responses API می‌روند | +| 🏢 **Codex جداسازی فضای کاری** | چندین فضای کاری Codex در هر ایمیل — OAuth به درستی اتصالات را با شناسه فضای کاری جدا می کند | +| 🔄 **به روز رسانی خودکار الکترونیک** | برنامه دسکتاپ برای به روز رسانی ها + نصب خودکار در راه اندازی مجدد | -### 🤖 Agent & Protocol Operations (v2.0) +### 🤖 عملیات عامل و پروتکل (نسخه 2.0) -| Feature | What It Does | +| ویژگی | چه می کند | | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 🔧 **MCP Server (107 tools)** | IDE/agent tools via 3 transports: stdio, SSE (`/api/mcp/sse`), Streamable HTTP (`/api/mcp/stream`). 107 unique tools across the registered tool families; enabled skills may add dynamic tools at runtime | -| 🤝 **A2A Server (JSON-RPC + SSE)** | Agent-to-agent task execution with sync and streaming flows | -| 🧭 **Consolidated Endpoints Page** | Tabbed management page with Endpoint Proxy, MCP, A2A, and API Endpoints tabs | -| 🎚️ **Service Enable/Disable Toggles** | ON/OFF switches for MCP and A2A with settings persistence (default: OFF) | -| 🛰️ **MCP Runtime Heartbeat** | Real process status (pid, uptime, heartbeat age, transport, scope mode) | -| 📋 **MCP Audit Trail** | Filterable audit logs with success/failure and key attribution | -| 🔐 **MCP Scope Enforcement** | 32 granular scope permissions for controlled tool access | -| 📡 **A2A Task Lifecycle Management** | List/filter tasks, inspect events/artifacts, cancel running tasks | -| 📋 **Agent Card Discovery** | `/.well-known/agent.json` for client auto-discovery | -| 🧪 **Protocol E2E Test Harness** | Real MCP SDK + A2A client flows in `test:protocols:e2e` | -| ⚙️ **Operational Controls** | Switch combos, tune resilience settings, and review breaker state from dedicated Health and Settings surfaces | +| 🔧 **سرور MCP (107 ابزار)** | ابزار IDE/عامل از طریق 3 انتقال: stdio، SSE (`/api/mcp/sse`)، HTTP قابل جریان (`/api/mcp/stream`). 107 ابزار منحصر به فرد در میان خانواده ابزارهای ثبت شده؛ مهارت‌های فعال ممکن است ابزارهای پویا را در زمان اجرا اضافه کنند | +| 🤝 **سرور A2A (JSON-RPC + SSE)** | اجرای کار عامل به عامل با همگام سازی و جریان های جریانی | +| 🧭 **صفحه نقاط پایانی تلفیقی** | صفحه مدیریت زبانه‌دار با برگه‌های Endpoint Proxy، MCP، A2A، و API Endpoints | +| 🎚️ **سرویس فعال/غیرفعال کردن ضامن ها** | کلیدهای روشن/خاموش برای MCP و A2A با تداوم تنظیمات (پیش‌فرض: OFF) | +| 🛰️ **MCP زمان اجرا Heartbeat** | وضعیت واقعی فرآیند (pid، uptime، سن ضربان قلب، حمل و نقل، حالت دامنه) | +| 📋 **MCP مسیر حسابرسی** | گزارش های حسابرسی قابل فیلتر با موفقیت/شکست و اسناد کلیدی | +| 🔐 ** MCP Scope Enforcement ** | 32 مجوز granular scope برای دسترسی به ابزار کنترل شده | +| 📡 **A2A مدیریت چرخه حیات وظیفه** | فهرست/فیلتر کردن وظایف، بازرسی رویدادها/مصنوعات، لغو وظایف در حال اجرا | +| 📋 **کشف کارت نماینده** | `/.well-known/agent.json` برای کشف خودکار مشتری | +| 🧪 **آرنج تست پروتکل E2E** | Real MCP SDK + A2A کلاینت در `test:protocols:e2e` جریان می یابد | +| ⚙️ **کنترل های عملیاتی** | جابجایی ترکیب‌ها، تنظیم تنظیمات انعطاف‌پذیری و بررسی وضعیت شکن از سطوح اختصاصی Health و Settings | -### 🧠 Routing & Intelligence +### 🧠 مسیریابی و هوشمندی -| Feature | What It Does | +| ویژگی | چه می کند | | ---------------------------------- | ------------------------------------------------------------------------ | -| 🎯 **Smart 4-Tier Fallback** | Auto-route: Subscription → API Key → Cheap → Free | -| 📊 **Real-Time Quota Tracking** | Live token count + reset countdown per provider | -| 🔄 **Format Translation** | OpenAI ↔ Claude ↔ Gemini ↔ Responses with schema-safe conversions | -| 👥 **Multi-Account Support** | Multiple accounts per provider with intelligent selection | -| 🔄 **Auto Token Refresh** | OAuth tokens refresh automatically with retry | -| 🎨 **Custom Combos** | 13 balancing strategies + fallback chain control | -| 🔗 **Context Relay** | Session continuity handoffs when account rotation happens mid-session | -| 🌐 **Wildcard Router** | `provider/*` dynamic routing | -| 🧠 **Thinking Budget Controls** | Passthrough, auto, custom, and adaptive reasoning limits | -| 🔀 **Model Aliases** | Built-in + custom model aliasing and migration safety | -| ⚡ **Background Degradation** | Route low-priority background tasks to cheaper models | -| 🧪 **Task-Aware Smart Routing** | Auto-select model by content type (coding/vision/analysis/summarization) | -| 🔄 **A2A Agent Workflows** | Deterministic FSM orchestrator for stateful multi-step agent executions | -| 🔀 **Adaptive Routing** | Dynamic strategy override based on token volume and prompt complexity | -| 🎲 **Provider Diversity** | Shannon entropy scoring balancing auto-combo traffic distribution | -| 💬 **System Prompt Injection** | Global behavior controls applied consistently | -| 📄 **Responses API Compatibility** | Full `/v1/responses` support for Codex and advanced agentic workflows | +| 🎯 **هوشمند 4 طبقه بازگشتی ** | مسیر خودکار: اشتراک → کلید API → ارزان → رایگان | +| 📊 **ردیابی سهمیه بی درنگ** | تعداد توکن زنده + بازنشانی شمارش معکوس برای هر ارائه دهنده | +| 🔄 **ترجمه فرمت** | OpenAI ↔ Claude ↔ Gemini ↔ پاسخ با تبدیل های ایمن طرحواره | +| 👥 **پشتیبانی چند حساب ** | چندین حساب در هر ارائه دهنده با انتخاب هوشمند | +| 🔄 **بازسازی خودکار توکن** | توکن های OAuth به طور خودکار با تلاش مجدد | +| 🎨 **ترکیب های سفارشی** | 13 استراتژی متعادل سازی + کنترل زنجیره ای بازگشتی | +| 🔗 **رله زمینه** | وقتی چرخش حساب در اواسط جلسه اتفاق می‌افتد، تداوم جلسه ارسال می‌شود | +| 🌐 **روتر Wildcard** | مسیریابی پویا `provider/*` | +| 🧠 **تفکر کنترل های بودجه ** | محدودیت های استدلال گذرا، خودکار، سفارشی و تطبیقی ​​| +| 🔀 **نام مستعار مدل** | داخلی + مدل سفارشی نامگذاری و امنیت مهاجرت | +| ⚡ **تخریب پس زمینه** | مسیریابی وظایف پس زمینه با اولویت پایین به مدل های ارزان تر | +| 🧪 **مسیریابی هوشمند Task-Aware** | انتخاب خودکار مدل بر اساس نوع محتوا (کدگذاری/دید/تحلیل/خلاصه) | +| 🔄 ** گردش کار نماینده A2A ** | ارکستراتور قطعی FSM برای اجرای چند مرحله ای عامل | +| 🔀 **مسیریابی تطبیقی** | نادیده گرفتن استراتژی پویا بر اساس حجم توکن و پیچیدگی سریع | +| 🎲 **تنوع ارائه دهنده** | توزیع ترافیک خودکار ترکیبی متعادل کننده امتیاز آنتروپی شانون | +| 💬 **تزریق سریع سیستم** | کنترل های رفتار جهانی به طور مداوم اعمال می شود | +| 📄 **پاسخ ها سازگاری API ** | پشتیبانی کامل از `/v1/responses` برای Codex و گردش کار نمایندگی پیشرفته | -### 🎵 Multi-Modal APIs +### 🎵 API های چند وجهی -| Feature | What It Does | +| ویژگی | چه می کند | | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 🖼️ **Image Generation** | `/v1/images/generations` with cloud and local backends | -| 📐 **Embeddings** | `/v1/embeddings` for search and RAG pipelines | -| 🎤 **Audio Transcription** | `/v1/audio/transcriptions` — 7 providers (Deepgram Nova 3, AssemblyAI, Groq Whisper, HuggingFace, ElevenLabs, OpenAI, Azure), auto-language detection, MP4/MP3/WAV support | -| 🔊 **Text-to-Speech** | `/v1/audio/speech` — 10 providers (ElevenLabs, OpenAI, Deepgram, Cartesia, PlayHT, HuggingFace, Nvidia NIM, Inworld, Coqui, Tortoise) with correct error messages | -| 🎬 **Video Generation** | `/v1/videos/generations` (ComfyUI + SD WebUI workflows) | -| 🎵 **Music Generation** | `/v1/music/generations` (ComfyUI workflows) | -| 🛡️ **Moderations** | `/v1/moderations` safety checks | -| 🔀 **Reranking** | `/v1/rerank` for relevance scoring | -| 🔍 **Web Search** 🆕 | `/v1/search` — 5 providers (Serper, Brave, Perplexity, Exa, Tavily), 6,500+ free/month, auto-failover, cache | +| 🖼️ **تولید تصویر** | `/v1/images/generations` با ابر و باطن محلی | +| 📐 **جاسازی ها** | `/v1/embeddings` برای جستجو و خطوط لوله RAG | +| 🎤 **رونویسی صوتی** | `/v1/audio/transcriptions` — 7 ارائه دهنده (Deepgram Nova 3، AssemblyAI، Groq Whisper، HuggingFace، ElevenLabs، OpenAI، Azure)، تشخیص خودکار زبان، پشتیبانی MP4/MP3/WAV | +| 🔊 **متن به گفتار** | `/v1/audio/speech` — 10 ارائه دهنده (ElevenLabs، OpenAI، Deepgram، Cartesia، PlayHT، HuggingFace، Nvidia NIM، Inworld، Coqui، Tortoise) با پیام های خطای صحیح | +| 🎬 **نسل ویدیو** | `/v1/videos/generations` (گردش های کاری ComfyUI + SD WebUI) | +| 🎵 **نسل موسیقی** | `/v1/music/generations` (جریان کاری ComfyUI) | +| 🛡️ **اعتدال ** | `/v1/moderations` بررسی های ایمنی | +| 🔀 **رتبه بندی مجدد ** | `/v1/rerank` برای امتیازدهی مرتبط | +| 🔍 **جستجوی وب** 🆕 | `/v1/search` — 5 ارائه دهنده (Serper، Brave، Perplexity، Exa، Tavily)، بیش از 6500 رایگان در ماه، خودکار failover، کش | -### 🛡️ Resilience, Security & Governance +### 🛡️ تاب آوری، امنیت و حکمرانی -| Feature | What It Does | +| ویژگی | چه می کند | | ----------------------------------- | ------------------------------------------------------------------------------------------------------- | -| 🔌 **Provider Circuit Breakers** | Provider-wide trip/recover after fallback exhaustion with configurable thresholds | -| 🔒 **Daily Quota Lock** 🆕 | Detects exhaustion signals and locks routing for the specific model until midnight | -| 🎯 **Endpoint-Aware Models** | Custom models declare supported endpoints + API format | -| 🛡️ **Anti-Thundering Herd** | Mutex + semaphore protections on retry/rate events | -| 🧠 **Semantic + Signature Cache** | Cost/latency reduction with two cache layers | -| ⚡ **Request Idempotency** | Duplicate protection window | -| 🔒 **TLS Fingerprint Spoofing** | Browser-like TLS fingerprint — **reduces bot detection and account flagging** | -| 🔏 **CLI Fingerprint Matching** | Matches native CLI request signatures — **reduces ban risk while preserving proxy IP** | -| 🌐 **IP Filtering** | Allowlist/blocklist control for exposed deployments | -| 🚦 **Request Queue & Pacing** | Configurable per-connection request buckets for RPM, spacing, concurrency, and max wait | -| 📉 **Graceful Degradation** | Multi-layer capability fallbacks protecting core gateway operations | -| 📜 **Config Audit Trail** | Diff-based change tracking preventing operational drift with simple rollbacks | -| ⏳ **Provider Health Sync** | Proactive token expiration monitoring triggering alerts before authorization failures | -| ❄️ **Connection Cooldown** | Retryable 408/429/5xx failures cool down a single connection with optional upstream hints | -| 🚪 **Auto-Disable Banned Accounts** | Permanently blocked token accounts can be disabled automatically | -| 🔑 **API Key Management + Scoping** | Secure key issuance/rotation and model/provider controls | -| 👁️ **Scoped API Key Reveal** 🆕 | Opt-in recovery of API keys via `ALLOW_API_KEY_REVEAL` | -| 🛡️ **Protected `/models`** | Optional auth gating and provider hiding for model catalog | -| 🛡️ **Safe Outbound Fetch** 🆕 | Guarded fetch for provider calls — blocks private/local URLs, retries, SSRF protection | -| ⏳ **Wait For Cooldown** 🆕 | Auto-retry chat after connection cooldowns; configurable `enabled`, `maxRetries`, and `maxRetryWaitSec` | -| 🔍 **Runtime Env Validation** 🆕 | Zod-based env schema validation at startup with actionable error messages | -| 📋 **Compliance Audit v2** 🆕 | Pagination, request context, auth events, provider CRUD, and SSRF-blocked logging | +| 🔌 **ارائه دهنده مدار شکن** | سفر/بازیابی در سراسر ارائه دهنده پس از خستگی مجدد با آستانه های قابل تنظیم | +| 🔒 **قفل سهمیه روزانه** 🆕 | سیگنال های خستگی را تشخیص می دهد و مسیر را برای مدل خاص تا نیمه شب قفل می کند | +| 🎯 **مدل های آگاه از نقطه پایانی** | مدل های سفارشی نقاط پایانی پشتیبانی شده + قالب API | +| 🛡️ **گله ضد رعد** | محافظت‌های Mutex + سمافور در رویدادهای امتحان مجدد/نرخ دادن | +| 🧠 ** کش معنایی + امضا ** | کاهش هزینه/تأخیر با دو لایه کش | +| ⚡ **درخواست عدم توانمندی** | پنجره حفاظتی تکراری | +| 🔒 **تقلب اثر انگشت TLS** | اثر انگشت TLS شبیه مرورگر — **تشخیص ربات و پرچم گذاری حساب را کاهش می دهد** | +| 🔏 **تطابق اثر انگشت CLI** | با امضاهای درخواستی CLI بومی مطابقت دارد — **با حفظ IP پروکسی خطر ممنوعیت را کاهش می دهد** | +| 🌐 **فیلتر IP** | کنترل لیست مجاز/فهرست مسدود برای استقرارهای در معرض | +| 🚦 **درخواست صف و سرعت** | قابل تنظیم سطل درخواست در هر اتصال برای RPM، فاصله، همزمانی، و حداکثر انتظار | +| 📉 **تحقیر برازنده** | قابلیت چندلایه بازگشتی برای محافظت از عملیات دروازه اصلی | +| 📜 **پیکربندی مسیر حسابرسی** | ردیابی تغییر مبتنی بر تفاوت که از رانش عملیاتی با برگشت‌های ساده جلوگیری می‌کند | +| ⏳ **همگام سازی ارائه دهنده سلامت** | پیشگیرانه نظارت بر انقضای توکن هشدارهای راه اندازی قبل از خرابی مجوز | +| ❄️ **خنک کننده اتصال** | خطاهای 408/429/5xx قابل امتحان مجدد یک اتصال را با نکات بالادستی اختیاری خنک می کند | +| 🚪 ** غیرفعال کردن خودکار حساب های ممنوعه ** | حساب‌های توکن مسدود شده برای همیشه به‌طور خودکار غیرفعال می‌شوند | +| 🔑 **API کلید مدیریت + محدوده** | کنترل ایمن صدور/چرخش کلید و مدل/ارائه دهنده | +| 👁️ **نمایش کلید API با محدوده** 🆕 | بازیابی کلیدهای API از طریق `ALLOW_API_KEY_REVEAL` | +| 🛡️ **محافظت شده `/models`** | درگاه تأیید اختیاری و مخفی کردن ارائه دهنده برای کاتالوگ مدل | +| 🛡️ ** واکشی ایمن خروجی** 🆕 | واکشی محافظت شده برای تماس های ارائه دهنده — URL های خصوصی/محلی را مسدود می کند، تلاش های مجدد، حفاظت SSRF | +| ⏳ **منتظر خنک شدن باشید** 🆕 | سعی مجدد خودکار چت پس از خنک شدن اتصال. قابل تنظیم `enabled`، `maxRetries`، و `maxRetryWaitSec` | +| 🔍 **Runtime Env Validation** 🆕 | اعتبار سنجی طرحواره env مبتنی بر Zod در هنگام راه اندازی با پیام های خطای قابل اجرا | +| 📋 **ممیزی انطباق v2** 🆕 | صفحه بندی، زمینه درخواست، رویدادهای احراز هویت، ارائه دهنده CRUD، و ورود به سیستم مسدود شده با SSRF | -### 📊 Observability & Analytics +### 📊 قابلیت مشاهده و تجزیه و تحلیل -| Feature | What It Does | +| ویژگی | چه می کند | | -------------------------------- | ----------------------------------------------------- | -| 📝 **Request + Proxy Logging** | Full request/response and proxy logging | -| 📉 **Streamed Detailed Logs** | Reconstructs SSE payload streams cleanly into the UI | -| 🏷️ **Real-Time Model Badges** 🆕 | Live model status and daily quota countdown timers | -| 📋 **Unified Logs Dashboard** | Request, proxy, audit, and console views in one page | -| 🔍 **Request Telemetry** | p50/p95/p99 latency and request tracing | -| 🏥 **Health Dashboard** | Uptime, breaker states, lockouts, cache stats | -| 💰 **Cost Tracking** | Budget controls and per-model pricing visibility | -| 📈 **Analytics Visualizations** | Model/provider usage insights and trend views | -| 🧪 **Evaluation Framework** | Golden set testing with configurable match strategies | -| 📡 **Live Diagnostics** 🆕 | Semantic cache bypass for accurate combo live testing | -| 🔐 **TPS Log Metric** 🆕 | Tokens Per Second badge in log details modal | +| 📝 **درخواست + ثبت پروکسی** | درخواست/پاسخ کامل و ثبت پروکسی | +| 📉 **گزارشهای تفصیلی جریانی** | جریان های بار محموله SSE را به طور تمیز در UI بازسازی می کند | +| 🏷️ **نشان های مدل بلادرنگ ** 🆕 | وضعیت مدل زنده و تایمرهای شمارش معکوس سهمیه روزانه | +| 📋 **داشبورد گزارش های یکپارچه** | نماهای درخواست، پروکسی، ممیزی و کنسول در یک صفحه | +| 🔍 **درخواست تله متری** | تأخیر p50/p95/p99 و ردیابی درخواست | +| 🏥 **داشبورد سلامت** | Uptime، حالت های قطع کننده، قفل ها، آمار حافظه پنهان | +| 💰 **پیگیری هزینه** | کنترل های بودجه و مشاهده قیمت گذاری هر مدل | +| 📈 **تجسم های تحلیلی** | بینش استفاده از مدل/ارائه دهنده و نماهای روند | +| 🧪 **چارچوب ارزشیابی** | تست مجموعه طلایی با استراتژی های تطبیق قابل تنظیم | +| 📡 **تشخیص زنده** 🆕 | دور زدن حافظه پنهان معنایی برای آزمایش زنده ترکیبی دقیق | +| 🔐 **TPS Log Metric** 🆕 | نشان توکن در ثانیه در جزئیات گزارش معین | -### ☁️ Deployment & Platform +### ☁️ استقرار و پلتفرم -| Feature | What It Does | +| ویژگی | چه می کند | | ------------------------------ | --------------------------------------------------------------------- | -| 🌐 **Deploy Anywhere** | Localhost, VPS, Docker, Cloud environments | -| 🚇 **Cloudflare Tunnel** 🆕 | One-click Quick Tunnel integration from the dashboard | -| 🔑 **API Key Model Filtering** | Native /v1/models response filtered via assigned Bearer context roles | -| ⚡ **Smart Cache Bypass** | Configurable TTL heuristics and forced refetch controls | -| 🔄 **Backup/Restore** | Export/import and disaster recovery flows | -| 🧙 **Onboarding Wizard** | First-run guided setup | -| 🔧 **CLI Tools Dashboard** | One-click setup for popular coding tools | -| 🎮 **Model Playground** | Test any provider/model/endpoint from the dashboard | -| 🔏 **CLI Fingerprint Toggle** | Per-provider fingerprint matching in Settings > Security | -| 🌐 **i18n (30 languages)** | Full dashboard + docs language support with RTL coverage | -| 🧹 **Clear All Models** | One-click model list clearing in provider details | -| 👁️ **Sidebar Controls** 🆕 | Hide components and integrations from Appearance Settings | -| 📋 **Issue Templates** | Standardized GitHub templates for bugs and features | -| 📂 **Custom Data Directory** | `DATA_DIR` override for storage location | -| 🌐 **V1 WebSocket Bridge** 🆕 | OpenAI-compatible WebSocket traffic proxied via `/v1/ws` | -| 🔑 **Sync Tokens & Bundle** 🆕 | Config sync tokens + versioned bundle endpoint with ETag support | +| 🌐 **استقرار در هر کجا ** | Localhost، VPS، Docker، محیط های ابری | +| 🚇 **Cloudflare تونل** 🆕 | ادغام Quick Tunnel با یک کلیک از داشبورد | +| 🔑 ** فیلتر مدل کلید API ** | پاسخ بومی /v1/models از طریق نقش‌های زمینه حامل اختصاص داده شده فیلتر شده است +| ⚡ **عملیات کش هوشمند** | اکتشافی TTL قابل تنظیم و کنترل های بازیابی اجباری | +| 🔄 **پشتیبان گیری/بازیابی** | صادرات/واردات و جریان های بازیابی بلایا | +| 🧙 **جادوگر سوار شدن** | راه اندازی هدایت شده در اولین اجرا | +| 🔧 **CLI Tools Dashboard ** | راه اندازی با یک کلیک برای ابزارهای کدنویسی محبوب | +| 🎮 **مدل زمین بازی** | هر ارائه دهنده/مدل/نقطه پایانی را از داشبورد تست کنید | +| 🔏 **ضامن اثر انگشت CLI** | مطابقت اثر انگشت هر ارائه دهنده در تنظیمات > امنیت | +| 🌐 **i18n (30 زبان)** | داشبورد کامل + پشتیبانی از زبان اسناد با پوشش RTL | +| 🧹 **پاک کردن همه مدل ها** | پاک کردن لیست مدل با یک کلیک در جزئیات ارائه دهنده | +| 👁️ **کنترل های نوار کناری** 🆕 | مخفی کردن اجزا و ادغام ها از تنظیمات ظاهر | +| 📋 **نمونه های شماره** | الگوهای استاندارد GitHub برای اشکالات و ویژگی ها | +| 📂 **دایرکتوری داده های سفارشی** | لغو `DATA_DIR` برای مکان ذخیره سازی | +| 🌐 **V1 WebSocket Bridge** 🆕 | ترافیک OpenAI سازگار با WebSocket پروکسی شده از طریق `/v1/ws` | +| 🔑 **همگام سازی توکن ها و بسته ها** 🆕 | پیکربندی نشانه‌های همگام‌سازی + نسخه نهایی بسته نرم‌افزاری با پشتیبانی ETag | -### Feature Deep Dive +### ویژگی Deep Dive -#### Smart fallback with practical cost control +#### بازگشت هوشمند با کنترل هزینه عملی ```txt Combo: "my-coding-stack" @@ -1504,73 +1504,73 @@ Combo: "my-coding-stack" 4. if/kimi-k2-thinking ``` -When quota, rate, or health fails, OmniRoute automatically moves to the next candidate without manual switching. +هنگامی که سهمیه، نرخ، یا سلامت ناموفق باشد، OmniRoute به طور خودکار بدون تغییر دستی به نامزد بعدی منتقل می شود. -#### Protocol management that is visible and operable +#### مدیریت پروتکل قابل مشاهده و قابل اجرا -- MCP + A2A are discoverable in UI and docs (not hidden) -- Protocol status APIs expose live operational data (`/api/mcp/*`, `/api/a2a/*`) -- Dashboards include actions for day-2 ops (combo toggles, breaker resets, task cancellation) +- MCP + A2A در رابط کاربری و اسناد قابل کشف هستند (پنهان نمی شوند) +- APIهای وضعیت پروتکل داده‌های عملیاتی زنده را در معرض دید قرار می‌دهند (`/api/mcp/*`، `/api/a2a/*`) +- داشبوردها شامل اقداماتی برای عملیات روز دوم هستند (تغییرهای ترکیبی، بازنشانی قطع کننده، لغو کار) -#### Translator + validation workflow +#### مترجم + گردش کار اعتبار سنجی -The Translator area includes: +منطقه مترجم شامل: -- **Playground**: request transformation checks -- **Chat Tester**: full request/response round-trip -- **Test Bench**: multiple cases in one run -- **Live Monitor**: real-time traffic view +- **زمین بازی**: درخواست بررسی تبدیل +- **تستر چت**: درخواست/پاسخ کامل رفت و برگشت +- **میز تست **: موارد متعدد در یک اجرا +- ** مانیتور زنده **: نمایش ترافیک در زمان واقعی -Plus protocol validation with real clients via `npm run test:protocols:e2e`. +اعتبار سنجی پروتکل پلاس با مشتریان واقعی از طریق `npm run test:protocols:e2e`. -> 📖 **[MCP Server README](open-sse/mcp-server/README.md)** — Tool reference, IDE configs, and client examples +> 📖 **[MCP سرور README](open-sse/mcp-server/README.md)** — مرجع ابزار، تنظیمات IDE و نمونه های مشتری > -> 📖 **[A2A Server README](src/lib/a2a/README.md)** — Skills, JSON-RPC methods, streaming, and task lifecycle +> 📖 **[A2A سرور README](src/lib/a2a/README.md)** — مهارت ها، روش های JSON-RPC، جریان و چرخه عمر کار -## 🧪 Evaluations (Evals) +## 🧪 ارزیابی ها (ارزیابی ها) -OmniRoute includes a built-in evaluation framework to test LLM response quality against a golden set. Access it via **Analytics → Evals** in the dashboard. +OmniRoute شامل یک چارچوب ارزیابی داخلی برای آزمایش کیفیت پاسخ LLM در برابر یک مجموعه طلایی است. از طریق **Analytics → Evals** در داشبورد به آن دسترسی داشته باشید. -### Built-in Golden Set +### ست طلایی توکار -The pre-loaded "OmniRoute Golden Set" contains test cases for: +«مجموعه طلایی OmniRoute» از پیش بارگذاری شده حاوی موارد آزمایشی برای موارد زیر است: -- Greetings, math, geography, code generation -- JSON format compliance, translation, markdown generation -- Safety refusal (harmful content), counting, boolean logic +- با سلام، ریاضی، جغرافیا، تولید کد +- مطابقت با فرمت JSON، ترجمه، تولید علامت گذاری +- امتناع ایمنی (محتوای مضر)، شمارش، منطق بولی -### Evaluation Strategies +### استراتژی های ارزیابی -| Strategy | Description | Example | +| استراتژی | توضیحات | مثال | | ---------- | ------------------------------------------------ | -------------------------------- | -| `exact` | Output must match exactly | `"4"` | -| `contains` | Output must contain substring (case-insensitive) | `"Paris"` | -| `regex` | Output must match regex pattern | `"1.*2.*3"` | -| `custom` | Custom JS function returns true/false | `(output) => output.length > 10` | +| `exact` | خروجی باید دقیقاً مطابقت داشته باشد | `"4"` | +| `contains` | خروجی باید حاوی رشته فرعی (بدون حساس به بزرگی) | `"Paris"` | +| `regex` | خروجی باید با الگوی regex مطابقت داشته باشد | `"1.*2.*3"` | +| `custom` | تابع JS سفارشی true/false | `(output) => output.length > 10` | --- -## 📖 Setup Guide +## 📖 راهنمای راه اندازی -### Protocol Setup (MCP + A2A) +### راه اندازی پروتکل (MCP + A2A)
🧩 MCP Setup (Model Context Protocol) -Start MCP transport in stdio mode: +حمل و نقل MCP را در حالت stdio شروع کنید: ```bash omniroute --mcp ``` -Recommended validation flow: +جریان اعتبارسنجی توصیه شده: -1. Connect your MCP client over stdio. -2. Run `omniroute_get_health`. -3. Run `omniroute_list_combos`. -4. Open `/dashboard/mcp` to confirm heartbeat, activity, and audit. +1. مشتری MCP خود را از طریق stdio وصل کنید. +2. `omniroute_get_health` را اجرا کنید. +3. `omniroute_list_combos` را اجرا کنید. +4. `/dashboard/mcp` را برای تأیید ضربان قلب، فعالیت و ممیزی باز کنید. -Useful APIs for automation: +APIهای مفید برای اتوماسیون: - `GET /api/mcp/status` - `GET /api/mcp/tools` @@ -1582,13 +1582,13 @@ Useful APIs for automation:
🤝 A2A Setup (Agent2Agent) -Discover the agent: +عامل را کشف کنید: ```bash curl http://localhost:20128/.well-known/agent.json ``` -Send a task: +ارسال یک کار: ```bash curl -X POST http://localhost:20128/a2a \ @@ -1596,40 +1596,40 @@ curl -X POST http://localhost:20128/a2a \ -d '{"jsonrpc":"2.0","id":"setup-a2a","method":"message/send","params":{"skill":"quota-management","messages":[{"role":"user","content":"Summarize quota status."}]}}' ``` -Manage lifecycle: +مدیریت چرخه عمر: - `GET /api/a2a/status` - `GET /api/a2a/tasks` - `GET /api/a2a/tasks/:id` - `POST /api/a2a/tasks/:id/cancel` -Operational UI: +رابط کاربری عملیاتی: -- `/dashboard/a2a` for task/state/stream observability and smoke actions +- `/dashboard/a2a` برای قابلیت مشاهده وظیفه/وضعیت/جریان و اقدامات دود
🧪 End-to-end protocol validation -Validate both protocols with real clients: +هر دو پروتکل را با کلاینت های واقعی اعتبار سنجی کنید: ```bash npm run test:protocols:e2e ``` -This verifies: +این تأیید می کند: -- MCP SDK client connect/list/call -- A2A discovery/send/stream/get/cancel -- Cross-check data in MCP audit and A2A task management APIs +- اتصال/لیست/تماس کلاینت MCP SDK +- A2A کشف / ارسال / جریان / دریافت / لغو +- بررسی متقاطع داده ها در ممیزی MCP و APIهای مدیریت وظایف A2A
💳 Subscription Providers -### Claude Code (Pro/Max) +کد ### Claude (Pro/Max) ```bash Dashboard → Providers → Connect Claude Code @@ -1642,7 +1642,7 @@ Models: cc/claude-haiku-4-5-20251001 ``` -**Pro Tip:** Use Opus for complex tasks, Sonnet for speed. OmniRoute tracks quota per model! +**نکته حرفه ای:** از Opus برای کارهای پیچیده و Sonnet برای سرعت استفاده کنید. OmniRoute سهمیه هر مدل را دنبال می کند! ### OpenAI Codex (Plus/Pro) @@ -1656,22 +1656,22 @@ Models: cx/gpt-5.1-codex-max ``` -#### Codex Account Limit Management (5h + Weekly) +#### Codex مدیریت محدودیت حساب (5 ساعت + هفتگی) -Each Codex account now has policy toggles in `Dashboard -> Providers`: +هر حساب Codex اکنون دارای تغییر سیاست در `Dashboard -> Providers` است: -- `5h` (ON/OFF): enforce the 5-hour window threshold policy. -- `Weekly` (ON/OFF): enforce the weekly window threshold policy. -- Threshold behavior: when an enabled window reaches >=90% usage, that account is skipped. -- Rotation behavior: OmniRoute routes to the next eligible Codex account automatically. -- Reset behavior: when the provider `resetAt` time passes, the account becomes eligible again automatically. +- `5h` (روشن/خاموش): سیاست آستانه پنجره 5 ساعته را اجرا کنید. +- `Weekly` (روشن/خاموش): سیاست آستانه پنجره هفتگی را اجرا کنید. +- رفتار آستانه: هنگامی که یک پنجره فعال به >=90 درصد استفاده می رسد، آن حساب حذف می شود. +- رفتار چرخش: OmniRoute به طور خودکار به حساب بعدی واجد شرایط Codex مسیر می‌دهد. +- رفتار بازنشانی: هنگامی که زمان ارائه دهنده `resetAt` می گذرد، حساب دوباره به طور خودکار واجد شرایط می شود. Scenarios: -- `5h ON` + `Weekly ON`: account is skipped when either window reaches threshold. -- `5h OFF` + `Weekly ON`: only weekly usage can block the account. -- `5h ON` + `Weekly OFF`: only 5-hour usage can block the account. -- `resetAt` passed: account re-enters rotation automatically (no manual re-enable). +- `5h ON` + `Weekly ON`: هنگامی که هر یک از پنجره ها به آستانه می رسد حساب حذف می شود. +- `5h OFF` + `Weekly ON`: فقط استفاده هفتگی می تواند حساب را مسدود کند. +- `5h ON` + `Weekly OFF`: فقط استفاده 5 ساعته می تواند حساب را مسدود کند. +- `resetAt` تصویب شد: حساب به طور خودکار دوباره وارد چرخش می شود (بدون فعال کردن مجدد دستی). ### GitHub Copilot @@ -1691,88 +1691,88 @@ Models:
🔑 API Key Providers -### NVIDIA NIM (FREE developer access — 70+ models) +### NVIDIA NIM (دسترسی رایگان برنامه نویس - بیش از 70 مدل) -1. Sign up: [build.nvidia.com](https://build.nvidia.com) -2. Get free API key (1000 inference credits included) -3. Dashboard → Add Provider → NVIDIA NIM: - - API Key: `nvapi-your-key` +1. ثبت نام کنید: [build.nvidia.com](https://build.nvidia.com) +2. کلید API رایگان دریافت کنید (1000 اعتبار استنتاج شامل) +3. داشبورد → افزودن ارائه دهنده → NVIDIA NIM: + - کلید API: `nvapi-your-key` -**Models:** `nvidia/llama-3.3-70b-instruct`, `nvidia/mistral-7b-instruct`, and 50+ more +**مدل ها:** `nvidia/llama-3.3-70b-instruct`، `nvidia/mistral-7b-instruct`، و بیش از 50 مدل دیگر -**Pro Tip:** OpenAI-compatible API — works seamlessly with OmniRoute's format translation! +** نکته حرفه ای: ** OpenAI سازگار با API - با ترجمه فرمت OmniRoute یکپارچه کار می کند! ### DeepSeek -1. Sign up: [platform.deepseek.com](https://platform.deepseek.com) -2. Get API key -3. Dashboard → Add Provider → DeepSeek +1. ثبت نام کنید: [platform.deepseek.com](https://platform.deepseek.com) +2. کلید API را دریافت کنید +3. داشبورد → افزودن ارائه دهنده → DeepSeek -**Models:** `deepseek/deepseek-chat`, `deepseek/deepseek-coder` +**مدل ها:** `deepseek/deepseek-chat`، `deepseek/deepseek-coder` -### Groq (Free Tier Available!) +### Groq (سطح رایگان موجود است!) -1. Sign up: [console.groq.com](https://console.groq.com) -2. Get API key (free tier included) -3. Dashboard → Add Provider → Groq +1. ثبت نام کنید: [console.groq.com](https://console.groq.com) +2. کلید API را دریافت کنید (شامل ردیف رایگان) +3. داشبورد → افزودن ارائه دهنده → Groq -**Models:** `groq/llama-3.3-70b`, `groq/mixtral-8x7b` +**مدل ها:** `groq/llama-3.3-70b`، `groq/mixtral-8x7b` -**Pro Tip:** Ultra-fast inference — best for real-time coding! +** نکته حرفه ای: ** استنتاج فوق العاده سریع - بهترین برای برنامه نویسی در زمان واقعی! -### OpenRouter (100+ Models) +### OpenRouter (100+ مدل) -1. Sign up: [openrouter.ai](https://openrouter.ai) -2. Get API key -3. Dashboard → Add Provider → OpenRouter +1. ثبت نام کنید: [openrouter.ai](https://openrouter.ai) +2. کلید API را دریافت کنید +3. داشبورد → افزودن ارائه دهنده → OpenRouter -**Models:** Access 100+ models from all major providers through a single API key. +**مدل ها:** از طریق یک کلید API به بیش از 100 مدل از همه ارائه دهندگان اصلی دسترسی پیدا کنید. -**Dashboard behavior:** OpenRouter models are managed from **Available Models**. Manual add, import, and auto-sync all update the same list. +**رفتار داشبورد:** مدل های OpenRouter از **مدل های موجود** مدیریت می شوند. افزودن دستی، وارد کردن، و همگام‌سازی خودکار همه یک لیست را به‌روزرسانی می‌کنند.
💰 Cheap Providers (Backup) -### GLM-4.7 (Daily reset, $0.6/1M) +### GLM-4.7 (بازنشانی روزانه، 0.6/1 میلیون دلار) -1. Sign up: [Zhipu AI](https://open.bigmodel.cn/) -2. Get API key from Coding Plan -3. Dashboard → Add API Key: - - Provider: `glm` - - API Key: `your-key` +1. ثبت نام: [Zhipu AI](https://open.bigmodel.cn/) +2. کلید API را از برنامه کدگذاری دریافت کنید +3. داشبورد ← افزودن کلید API: + - ارائه دهنده: `glm` + - کلید API: `your-key` -**Use:** `glm/glm-4.7` +**استفاده:** `glm/glm-4.7` -**Pro Tip:** Coding Plan offers 3× quota at 1/7 cost! Reset daily 10:00 AM. +** نکته حرفه ای: ** طرح برنامه نویسی سهمیه 3× را با هزینه 1/7 ارائه می دهد! بازنشانی روزانه 10:00 صبح. -### MiniMax M2.1 (5h reset, $0.20/1M) +### MiniMax M2.1 (5 ساعت بازنشانی، 0.20 دلار/1 میلیون دلار) -1. Sign up: [MiniMax](https://www.minimax.io/) -2. Get API key -3. Dashboard → Add API Key +1. ثبت نام کنید: [MiniMax](https://www.minimax.io/) +2. کلید API را دریافت کنید +3. داشبورد ← افزودن کلید API -**Use:** `minimax/MiniMax-M2.1` +**استفاده:** `minimax/MiniMax-M2.1` -**Pro Tip:** Cheapest option for long context (1M tokens)! +** نکته حرفه ای: ** ارزان ترین گزینه برای زمینه طولانی (1 میلیون توکن)! -### Kimi K2 ($9/month flat) +### Kimi K2 (9 دلار در ماه ثابت) -1. Subscribe: [Moonshot AI](https://platform.moonshot.ai/) -2. Get API key -3. Dashboard → Add API Key +1. مشترک شوید: [Moonshot AI](https://platform.moonshot.ai/) +2. کلید API را دریافت کنید +3. داشبورد ← افزودن کلید API -**Use:** `kimi/kimi-latest` +**استفاده:** `kimi/kimi-latest` -**Pro Tip:** Fixed $9/month for 10M tokens = $0.90/1M effective cost! +**نکته حرفه ای:** ثابت 9 دلار در ماه برای 10 میلیون توکن = 0.90 دلار / 1 میلیون هزینه موثر!
🆓 FREE Providers (Emergency Backup) -### Qoder (5 FREE models via OAuth) +### Qoder (5 مدل رایگان از طریق OAuth) ```bash Dashboard → Connect Qoder @@ -1787,7 +1787,7 @@ Models: if/deepseek-r1 ``` -### Qwen (4 FREE models via Device Code) +### Qwen (4 مدل رایگان از طریق کد دستگاه) ```bash Dashboard → Connect Qwen @@ -1799,7 +1799,7 @@ Models: qw/qwen3-coder-flash ``` -### Kiro (Claude FREE) +### Kiro (رایگان Claude) ```bash Dashboard → Connect Kiro @@ -1816,7 +1816,7 @@ Models:
🎨 Create Combos -### Example 1: Maximize Subscription → Cheap Backup +### مثال 1: حداکثر کردن اشتراک → پشتیبان گیری ارزان ``` Dashboard → Combos → Create New @@ -1830,7 +1830,7 @@ Models: Use in CLI: premium-coding ``` -### Example 2: Free-Only (Zero Cost) +### مثال 2: فقط رایگان (هزینه صفر) ``` Name: free-combo @@ -1855,9 +1855,9 @@ Settings → Models → Advanced: Model: cc/claude-opus-4-7 ``` -### Claude Code +### کد Claude -Use the **CLI Tools** page in the dashboard for one-click configuration, or edit `~/.claude/settings.json` manually. +از صفحه **CLI Tools** در داشبورد برای پیکربندی با یک کلیک استفاده کنید، یا `~/.claude/settings.json` را به صورت دستی ویرایش کنید. ### Codex CLI @@ -1870,13 +1870,13 @@ codex "your prompt" ### OpenClaw -**Option 1 — Dashboard (recommended):** +**گزینه 1 - داشبورد (توصیه می شود):** ``` Dashboard → CLI Tools → OpenClaw → Select Model → Apply ``` -**Option 2 — Manual:** Edit `~/.openclaw/openclaw.json`: +**گزینه 2 — دستی:** ویرایش `~/.openclaw/openclaw.json`: ```json { @@ -1892,7 +1892,7 @@ Dashboard → CLI Tools → OpenClaw → Select Model → Apply } ``` -> **Note:** OpenClaw only works with local OmniRoute. Use `127.0.0.1` instead of `localhost` to avoid IPv6 resolution issues. +> **توجه:** OpenClaw فقط با OmniRoute محلی کار می کند. از `127.0.0.1` به جای `localhost` برای جلوگیری از مشکلات وضوح IPv6 استفاده کنید. ### Cline / Continue / RooCode @@ -1906,7 +1906,7 @@ Settings → API Configuration: ### OpenCode -**Step 1:** Add OmniRoute as a custom provider: +**مرحله 1:** OmniRoute را به عنوان یک ارائه دهنده سفارشی اضافه کنید: ```bash opencode @@ -1914,7 +1914,7 @@ opencode # Select "Other" → Enter ID: "omniroute" → Enter your OmniRoute API key ``` -**Step 2:** Create/edit `opencode.json` in your project root: +**مرحله 2:** `opencode.json` را در ریشه پروژه خود ایجاد/ویرایش کنید: ```json { @@ -1936,123 +1936,123 @@ opencode } ``` -**Step 3:** Select the model in OpenCode: +**مرحله 3:** مدل را در OpenCode انتخاب کنید: ```bash /models # Select any OmniRoute model from the list ``` -> **Tip:** Add any model available in your OmniRoute `/v1/models` endpoint to the `models` section. Use the format `provider/model-id` from your OmniRoute dashboard. +> **نکته:** هر مدل موجود در نقطه پایانی OmniRoute `/v1/models` خود را به بخش `models` اضافه کنید. از قالب `provider/model-id` از داشبورد OmniRoute خود استفاده کنید.
--- -## Solución de Problemas +## راه حل مشکل
Click to expand troubleshooting guide -**"Language model did not provide messages"** +**"مدل زبان پیامی ارائه نکرد"** -- Provider quota exhausted → Check dashboard quota tracker -- Solution: Use combo fallback or switch to cheaper tier +- سهمیه ارائه دهنده تمام شده است → ردیاب سهمیه داشبورد را بررسی کنید +- راه حل: از ترکیبی جایگزین استفاده کنید یا به ردیف ارزان تر بروید -**Rate limiting** +**محدودیت نرخ** -- Subscription quota out → Fallback to GLM/MiniMax -- Add combo: `cc/claude-opus-4-7 → glm/glm-4.7 → if/kimi-k2-thinking` +- سهمیه اشتراک → بازگشت به GLM/MiniMax +- اضافه کردن ترکیبی: `cc/claude-opus-4-7 → glm/glm-4.7 → if/kimi-k2-thinking` -**OAuth token expired** +**توکن OAuth منقضی شده** -- Auto-refreshed by OmniRoute -- If issues persist: Dashboard → Provider → Reconnect +- به‌روزرسانی خودکار توسط OmniRoute +- در صورت وجود مشکلات: داشبورد → ارائه دهنده → اتصال مجدد -**High costs** +**هزینه های بالا** -- Check usage stats in Dashboard → Costs -- Switch primary model to GLM/MiniMax +- آمار استفاده را در داشبورد → هزینه ها بررسی کنید +- تغییر مدل اولیه به GLM/MiniMax -**Dashboard/API ports are wrong** +**پورت های داشبورد/API اشتباه هستند** -- `PORT` is the canonical base port (and API port by default) -- `API_PORT` overrides only OpenAI-compatible API listener -- `DASHBOARD_PORT` overrides only dashboard/Next.js listener -- Set `NEXT_PUBLIC_BASE_URL` to your dashboard/public URL (for OAuth callbacks) +- `PORT` پورت پایه متعارف است (و به طور پیش فرض درگاه API) +- `API_PORT` فقط شنونده OpenAI سازگار با API را لغو می کند +- `DASHBOARD_PORT` فقط شنونده داشبورد/Next.js را لغو می کند +- `NEXT_PUBLIC_BASE_URL` را روی داشبورد/URL عمومی خود تنظیم کنید (برای تماس های OAuth) -**Cloud sync errors** +**خطاهای همگام سازی ابری** -- Verify `BASE_URL` points to your running instance -- Verify `CLOUD_URL` points to your expected cloud endpoint -- Keep `NEXT_PUBLIC_*` values aligned with server-side values +- نقاط `BASE_URL` را به نمونه در حال اجرا خود تأیید کنید +- نقاط `CLOUD_URL` را به نقطه پایانی ابری مورد انتظار خود تأیید کنید +- مقادیر `NEXT_PUBLIC_*` را با مقادیر سمت سرور هماهنگ نگه دارید -**First login not working** +**لاگین اول کار نمی کند** -- Check `INITIAL_PASSWORD` in `.env` -- If unset, fallback password is `123456` +- `INITIAL_PASSWORD` را در `.env` بررسی کنید +- اگر تنظیم نشده باشد، رمز عبور بازگشتی `123456` است -**No request logs** +**بدون گزارش درخواست** -- `call_logs` in SQLite stores summary metadata for the Request Logs table and analytics views -- Detailed request/response payloads are written to `DATA_DIR/call_logs/` as one JSON artifact per request -- Enable pipeline capture from Dashboard → Logs → Request Logs if you need detailed per-stage payloads -- `Export Logs` reads the artifact files on demand, while `Export All` includes the `call_logs/` directory alongside `storage.sqlite` -- Set `APP_LOG_TO_FILE=true` if you also want application console logs in `logs/application/app.log` -- Adjust `APP_LOG_MAX_FILE_SIZE`, `APP_LOG_RETENTION_DAYS`, `APP_LOG_MAX_FILES`, and `CALL_LOG_MAX_ENTRIES` as needed +- `call_logs` در SQLite ابرداده های خلاصه را برای جدول Request Logs و نمایش های تجزیه و تحلیل ذخیره می کند +- محموله های درخواست/پاسخ تفصیلی به `DATA_DIR/call_logs/` به عنوان یک مصنوع JSON در هر درخواست نوشته می شود +- در صورت نیاز به محموله های دقیق در هر مرحله، ضبط خط لوله را از داشبورد → گزارش ها → گزارش های درخواستی فعال کنید +- `Export Logs` فایل های مصنوع را در صورت درخواست می خواند، در حالی که `Export All` شامل فهرست `call_logs/` در کنار `storage.sqlite` است +- اگر می خواهید گزارش های کنسول برنامه در `logs/application/app.log` نیز وجود داشته باشد، `APP_LOG_TO_FILE=true` را تنظیم کنید +- `APP_LOG_MAX_FILE_SIZE`، `APP_LOG_RETENTION_DAYS`، `APP_LOG_MAX_FILES`، و `CALL_LOG_MAX_ENTRIES` را در صورت نیاز تنظیم کنید -**Connection test shows "Invalid" for OpenAI-compatible providers** +**آزمایش اتصال "نامعتبر" را برای ارائه دهندگان سازگار با OpenAI نشان می دهد** -- Many providers don't expose a `/models` endpoint -- OmniRoute v1.0.6+ includes fallback validation via chat completions -- Ensure base URL includes `/v1` suffix +- بسیاری از ارائه دهندگان نقطه پایانی `/models` را افشا نمی کنند +- OmniRoute نسخه 1.0.6+ شامل اعتبار سنجی مجدد از طریق تکمیل چت است +- مطمئن شوید که پایه URL دارای پسوند `/v1` است -### 🔐 OAuth on a Remote Server +### 🔐 OAuth در یک سرور راه دور -> **⚠️ Important for users running OmniRoute on a VPS, Docker, or any remote server** +> **⚠️ برای کاربرانی که OmniRoute را روی VPS، Docker یا هر سرور راه دور اجرا می کنند مهم است** -The OAuth credentials bundled in OmniRoute are registered **for `localhost` only**. When you access OmniRoute on a remote server (e.g. `https://omniroute.myserver.com`), Google rejects the authentication with: +اعتبارنامه OAuth همراه با OmniRoute **فقط برای `localhost`** ثبت شده است. هنگامی که به OmniRoute در یک سرور راه دور (مثلاً `https://omniroute.myserver.com`) دسترسی دارید، Google احراز هویت را با: ``` Error 400: redirect_uri_mismatch ``` -#### Solution: Configure your own OAuth credentials +#### راه حل: اعتبار OAuth خود را پیکربندی کنید -You need to create an **OAuth 2.0 Client ID** in Google Cloud Console with your server's URI. +شما باید یک **OAuth 2.0 Client ID** در Google Cloud Console با URI سرور خود ایجاد کنید. -#### Step-by-step +#### گام به گام -**1. Open Google Cloud Console** +**1. باز کردن Google Cloud Console** -Go to: [https://console.cloud.google.com/apis/credentials](https://console.cloud.google.com/apis/credentials) +برو به: [https://console.cloud.google.com/apis/credentials](https://console.cloud.google.com/apis/credentials) -**2. Create a new OAuth 2.0 Client ID** +**2. یک شناسه مشتری OAuth 2.0 جدید ایجاد کنید** -- Click **"+ Create Credentials"** → **"OAuth client ID"** -- Application type: **"Web application"** -- Name: anything you like (e.g. `OmniRoute Remote`) +- روی **"+ ایجاد اعتبارنامه"** → **"OAuth شناسه مشتری"** کلیک کنید +- نوع برنامه: **"برنامه وب"** +- نام: هر چیزی که دوست دارید (به عنوان مثال `OmniRoute Remote`) -**3. Add Authorized Redirect URIs** +**3. URIهای مجاز تغییر مسیر را اضافه کنید** -In the **"Authorized redirect URIs"** field, add: +در قسمت **"URI های تغییر مسیر مجاز"**، اضافه کنید: ``` https://your-server.com/callback ``` -> Replace `your-server.com` with your server's domain or IP (include the port if needed, e.g. `http://45.33.32.156:20128/callback`). +> `your-server.com` را با دامنه یا IP سرور خود جایگزین کنید (در صورت نیاز پورت را اضافه کنید، به عنوان مثال `http://45.33.32.156:20128/callback`). -**4. Save and copy the credentials** +**4. اطلاعات کاربری را ذخیره و کپی کنید** -After creating, Google will show the **Client ID** and **Client Secret**. +پس از ایجاد، Google **شناسه مشتری** و **Client Secret** را نشان می دهد. -**5. Set environment variables** +**5. تنظیم متغیرهای محیط ** -In your `.env` (or Docker environment variables): +در `.env` (یا متغیرهای محیطی Docker): ```bash # For Antigravity: @@ -2063,7 +2063,7 @@ GEMINI_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com GEMINI_OAUTH_CLIENT_SECRET=GOCSPX-your-secret ``` -**6. Restart OmniRoute** +**6. راه اندازی مجدد OmniRoute** ```bash # npm: @@ -2073,114 +2073,114 @@ npm run dev docker restart omniroute ``` -**7. Try connecting again** +**7. دوباره سعی کنید وصل شوید** -Google will now redirect correctly to `https://your-server.com/callback`. +Google اکنون به درستی به `https://your-server.com/callback` تغییر مسیر می دهد. --- -#### Temporary workaround (without custom credentials) +#### راه حل موقت (بدون اعتبارنامه های سفارشی) -If you don't want to set up your own credentials right now, you can still use the **manual URL flow**: +اگر نمی‌خواهید اعتبار خود را در حال حاضر تنظیم کنید، همچنان می‌توانید از **جریان دستی URL** استفاده کنید: -1. OmniRoute opens the Google authorization URL -2. After authorizing, Google tries to redirect to `localhost` (which fails on the remote server) -3. **Copy the full URL** from your browser's address bar (even if the page doesn't load) -4. Paste that URL into the field shown in the OmniRoute connection modal -5. Click **"Connect"** +1. OmniRoute مجوز Google را باز می کند URL +2. پس از تأیید، Google سعی می‌کند به `localhost` تغییر مسیر دهد (که در سرور راه دور با مشکل مواجه می‌شود) +3. **URL** را از نوار آدرس مرورگر خود کپی کنید (حتی اگر صفحه بارگیری نشود) +4. آن URL را در فیلد نشان داده شده در مدال اتصال OmniRoute قرار دهید +5. روی **"اتصال"** کلیک کنید -> This works because the authorization code in the URL is valid regardless of whether the redirect page loaded. +> این کار به این دلیل کار می کند که کد مجوز در URL بدون توجه به بارگیری صفحه تغییر مسیر معتبر است. --- -## 🛠️ Tech Stack +## 🛠️ پشته فناوری
Click to expand tech stack details -- **Runtime**: Node.js 18–22 LTS (⚠️ Node.js 24+ is **not supported** — `better-sqlite3` native binaries are incompatible) -- **Language**: TypeScript 5.9 — **100% TypeScript** across `src/` and `open-sse/` (zero `any` in core modules since v2.0) -- **Framework**: Next.js 16 + React 19 + Tailwind CSS 4 -- **Database**: better-sqlite3 (SQLite) + LowDB (JSON legacy) — domain state, proxy logs, MCP audit, routing decisions, memory, skills -- **Schemas**: Zod (MCP tool I/O validation, API contracts) -- **Protocols**: MCP (stdio/HTTP) + A2A v0.3 (JSON-RPC 2.0 + SSE) -- **Streaming**: Server-Sent Events (SSE) -- **Auth**: OAuth 2.0 (PKCE) + JWT + API Keys + MCP Scoped Authorization -- **Testing**: Node.js test runner + Vitest (900+ tests including unit, integration, E2E) -- **CI/CD**: GitHub Actions (auto npm publish + Docker Hub on release) -- **Website**: [omniroute.online](https://omniroute.online) -- **Package**: [npmjs.com/package/omniroute](https://www.npmjs.com/package/omniroute) +- **زمان اجرا **: Node.js 18–22 LTS ( +- **زبان**: TypeScript 5.9 — **100% TypeScript** در `src/` و `open-sse/` (صفر `any` در ماژول های اصلی از نسخه 2.0) +- **فریم ورک**: Next.js 16 + React 19 + Tailwind CSS 4 +- **پایگاه داده**: بهتر-sqlite3 (SQLite) + LowDB (میراث JSON) - وضعیت دامنه، لاگ های پروکسی، ممیزی MCP، تصمیمات مسیریابی، حافظه، مهارت ها +- **طرحواره**: Zod (تأیید اعتبار I/O ابزار MCP، قراردادهای API) +- **پروتکل ها**: MCP (stdio/HTTP) + A2A نسخه 0.3 (JSON-RPC 2.0 + SSE) +- **جریان**: رویدادهای ارسال شده از سرور (SSE) +- **Auth**: OAuth 2.0 (PKCE) + کلیدهای JWT + API + مجوز محدوده MCP +- **تست**: Node.js تست دونده + Vitest (900+ تست شامل واحد، ادغام، E2E) +- **CI/CD**: اقدامات GitHub (انتشار خودکار npm + مرکز Docker در زمان انتشار) +- **وب سایت**: [omniroute.online](https://omniroute.online) +- **بسته**: [npmjs.com/package/omniroute](https://www.npmjs.com/package/omniroute) - **Docker**: [hub.docker.com/r/diegosouzapw/omniroute](https://hub.docker.com/r/diegosouzapw/omniroute) -- **Resilience**: Circuit breaker, exponential backoff, anti-thundering herd, TLS spoofing, auto-combo self-healing +- **ارتعاش**: قطع کننده مدار، عقب نشینی نمایی، گله ضد رعد و برق، جعل TLS، خودترمیمی خودکار ترکیبی
--- -## Documentación +## مستندات -| Document | Description | +| سند | توضیحات | | --------------------------------------------------------------------- | --------------------------------------------------- | -| [User Guide](docs/guides/USER_GUIDE.md) | Providers, combos, CLI integration, deployment | -| [API Reference](docs/reference/API_REFERENCE.md) | All endpoints with examples | -| [MCP Server](open-sse/mcp-server/README.md) | 107 MCP tools, IDE configs, Python/TS/Go clients | -| [A2A Server](src/lib/a2a/README.md) | JSON-RPC 2.0 protocol, skills, streaming, task mgmt | -| [Auto-Combo Engine](docs/auto-combo.md) | 13-factor scoring, mode packs, self-healing | -| [Context Relay](docs/features/context-relay.md) | Session handoff strategy for account rotation | -| [Troubleshooting](docs/guides/TROUBLESHOOTING.md) | Common problems and solutions | -| [Architecture](docs/architecture/ARCHITECTURE.md) | System architecture and internals | -| [Codebase Documentation](docs/architecture/CODEBASE_DOCUMENTATION.md) | Beginner-friendly codebase walkthrough | -| [Uninstall Guide](docs/guides/UNINSTALL.md) | Clean removal for all install methods | -| [Environment Config](docs/reference/ENVIRONMENT.md) | Complete `.env` variables and references | -| [Contributing](CONTRIBUTING.md) | Development setup and guidelines | -| [OpenAPI Spec](docs/reference/openapi.yaml) | OpenAPI 3.0 specification | -| [Security Policy](SECURITY.md) | Vulnerability reporting and security practices | -| [VM Deployment](docs/ops/VM_DEPLOYMENT_GUIDE.md) | Complete guide: VM + nginx + Cloudflare setup | -| [Features Gallery](docs/guides/FEATURES.md) | Visual dashboard tour with screenshots | -| [Release Checklist](docs/ops/RELEASE_CHECKLIST.md) | Pre-release validation steps | +| [راهنمای کاربر](docs/guides/USER_GUIDE.md) | ارائه دهندگان، ترکیب، یکپارچه سازی CLI، استقرار | +| [مرجع API](docs/reference/API_REFERENCE.md) | تمام نقاط پایانی با مثال | +| [سرور MCP](open-sse/mcp-server/README.md) | 107 ابزار MCP، تنظیمات IDE، کلاینت های Python/TS/Go | +| [سرور A2A](src/lib/a2a/README.md) | پروتکل JSON-RPC 2.0، مهارت ها، جریان، وظیفه mgmt | +| [موتور ترکیبی خودکار](docs/auto-combo.md) | امتیاز دهی 13 عاملی، بسته های حالت، خوددرمانی | +| [رله زمینه](docs/features/context-relay.md) | استراتژی انتقال جلسه برای چرخش حساب | +| [عیب یابی](docs/guides/TROUBLESHOOTING.md) | مشکلات و راه حل های رایج | +| [معماری](docs/architecture/ARCHITECTURE.md) | معماری سیستم و قطعات داخلی | +| [اسناد پایگاه کد](docs/architecture/CODEBASE_DOCUMENTATION.md) | راهنمای مبتدی مبتدی پایه کد | +| [راهنمای حذف نصب](docs/guides/UNINSTALL.md) | حذف پاک برای همه روش های نصب | +| [پیکربندی محیط](docs/reference/ENVIRONMENT.md) | تکمیل متغیرها و مراجع `.env` | +| [مشارکت](CONTRIBUTING.md) | راه اندازی و دستورالعمل های توسعه | +| [مشخصات OpenAPI](docs/reference/openapi.yaml) | مشخصات OpenAPI 3.0 | +| [سیاست امنیتی](SECURITY.md) | گزارش آسیب پذیری و شیوه های امنیتی | +| [استقرار VM](docs/ops/VM_DEPLOYMENT_GUIDE.md) | راهنمای کامل: راه اندازی VM + nginx + Cloudflare | +| [گالری امکانات](docs/guides/FEATURES.md) | تور داشبورد بصری با اسکرین شات | +| [چک لیست انتشار](docs/ops/RELEASE_CHECKLIST.md) | مراحل اعتبار سنجی پیش از انتشار | --- -## 🗺️ Roadmap +## 🗺️ نقشه راه -OmniRoute has **218+ features planned** across multiple development phases. Here are the key areas: +OmniRoute دارای **218+ ویژگی برنامه ریزی شده** در چندین فاز توسعه است. در اینجا مناطق کلیدی وجود دارد: -| Category | Planned Features | Highlights | +| دسته بندی | ویژگی های برنامه ریزی شده | نکات برجسته | | ----------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------- | -| 🧠 **Routing & Intelligence** | 25+ | Lowest-latency routing, tag-based routing, quota preflight, quota-aware P2C, step-based combo routing | -| 🔒 **Security & Compliance** | 20+ | SSRF hardening, credential cloaking, rate-limit per endpoint, management key scoping | -| 📊 **Observability** | 15+ | OpenTelemetry integration, real-time quota monitoring, combo target health, cost tracking per model | -| 🔄 **Provider Integrations** | 20+ | Dynamic model registry, connection cooldowns, multi-account Codex, Copilot quota parsing | -| ⚡ **Performance** | 15+ | Dual cache layer, prompt cache, response cache, streaming keepalive, batch API | -| 🌐 **Ecosystem** | 10+ | WebSocket API, config hot-reload, distributed config store, commercial mode | +| 🧠 **مسیریابی و هوشمندی** | 25+ | مسیریابی با کمترین تأخیر، مسیریابی مبتنی بر برچسب، پیش از پرواز سهمیه، P2C آگاه از سهمیه، مسیریابی ترکیبی مبتنی بر گام | +| 🔒 **امنیت و انطباق** | 20+ | سخت شدن SSRF، پوشاندن اعتبار، نرخ محدود در نقطه پایانی، محدوده کلید مدیریت | +| 📊 **قابلیت مشاهده** | 15+ | ادغام OpenTelemetry، نظارت بر سهمیه در زمان واقعی، سلامت هدف ترکیبی، ردیابی هزینه در هر مدل | +| 🔄 **یکپارچه سازی ارائه دهنده** | 20+ | رجیستری مدل پویا، خنک کننده اتصال، چند حساب Codex، تجزیه سهمیه Copilot | +| ⚡ **عملکرد** | 15+ | لایه کش دوگانه، کش سریع، حافظه پنهان پاسخ، جریان نگهدارنده، دسته ای API | +| 🌐 **اکوسیستم** | 10+ | WebSocket API، پیکربندی بارگذاری مجدد داغ، فروشگاه پیکربندی توزیع شده، حالت تجاری | -### 🔜 Coming Soon +### 🔜 به زودی -- 🔗 **OpenCode Integration** — Native provider support for the OpenCode AI coding IDE -- 🔗 **TRAE Integration** — Full support for the TRAE AI development framework -- 📦 **Batch API** — Asynchronous batch processing for bulk requests -- 🎯 **Tag-Based Routing** — Route requests based on custom tags and metadata -- 💰 **Lowest-Cost Strategy** — Automatically select the cheapest available provider +- 🔗 **ادغام OpenCode** — پشتیبانی ارائه دهنده بومی برای کدنویسی OpenCode AI IDE +- 🔗 **ادغام TRAE** — پشتیبانی کامل از چارچوب توسعه TRAE AI +- 📦 ** دسته ای API ** - پردازش دسته ای ناهمزمان برای درخواست های انبوه +- 🎯 **مسیریابی مبتنی بر برچسب** - درخواست های مسیر بر اساس برچسب ها و ابرداده های سفارشی +- 💰 **استراتژی کم هزینه** - ارزانترین ارائه دهنده موجود را به صورت خودکار انتخاب کنید -> 📝 Full feature specifications available in [`docs/new-features/`](docs/new-features/) (217 detailed specs) +> 📝 مشخصات کامل ویژگی موجود در [`docs/new-features/`](docs/new-features/) (217 مشخصات دقیق) --- -## 👥 Contributors +## 👥 مشارکت کنندگان [![Contributors](https://contrib.rocks/image?repo=diegosouzapw/OmniRoute&max=100&columns=20&anon=1)](https://github.com/diegosouzapw/OmniRoute/graphs/contributors) -### How to Contribute +### نحوه مشارکت -1. Fork the repository -2. Create your feature branch (`git checkout -b feature/amazing-feature`) -3. Commit your changes (`git commit -m 'Add amazing feature'`) -4. Push to the branch (`git push origin feature/amazing-feature`) -5. Open a Pull Request +1. مخزن را چنگال کنید +2. شاخه ویژگی خود را ایجاد کنید (`git checkout -b feature/amazing-feature`) +3. تغییرات خود را انجام دهید (`git commit -m 'Add amazing feature'`) +4. فشار به شاخه (`git push origin feature/amazing-feature`) +5. یک Pull Request را باز کنید -See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines. +برای دستورالعمل های دقیق به [CONTRIBUTING.md](CONTRIBUTING.md) مراجعه کنید. -### Releasing a New Version +### انتشار یک نسخه جدید ```bash # Create a release — npm publish happens automatically @@ -2189,7 +2189,7 @@ gh release create v2.0.0 --title "v2.0.0" --generate-notes --- -## 📊 Star History +## 📊 تاریخچه ستاره @@ -2209,15 +2209,15 @@ gh release create v2.0.0 --title "v2.0.0" --generate-notes -## 🙏 Acknowledgments +## 🙏 تشکر و قدردانی -Special thanks to **[CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI)** — the original Go implementation that inspired this JavaScript port. +تشکر ویژه از **[CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI)** - پیاده سازی اصلی Go که الهام بخش این پورت جاوا اسکریپت است. --- -## Licencia +## مجوز -MIT License - see [LICENSE](LICENSE) for details. +مجوز MIT - برای جزئیات بیشتر به [LICENSE](LICENSE) مراجعه کنید. --- diff --git a/docs/i18n/fa/llm.txt b/docs/i18n/fa/llm.txt index 1d98061631..4b324a992d 100644 --- a/docs/i18n/fa/llm.txt +++ b/docs/i18n/fa/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/fi/llm.txt b/docs/i18n/fi/llm.txt index 01fb1ec72b..92d30e036c 100644 --- a/docs/i18n/fi/llm.txt +++ b/docs/i18n/fi/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/fr/llm.txt b/docs/i18n/fr/llm.txt index b20f38d804..2b5cdefa71 100644 --- a/docs/i18n/fr/llm.txt +++ b/docs/i18n/fr/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/gu/llm.txt b/docs/i18n/gu/llm.txt index 3cabcd235f..d0f0f42f59 100644 --- a/docs/i18n/gu/llm.txt +++ b/docs/i18n/gu/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/he/llm.txt b/docs/i18n/he/llm.txt index d1dca10cc1..f8f0b3f644 100644 --- a/docs/i18n/he/llm.txt +++ b/docs/i18n/he/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/hi/llm.txt b/docs/i18n/hi/llm.txt index e88a70b26a..d79717b61e 100644 --- a/docs/i18n/hi/llm.txt +++ b/docs/i18n/hi/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/hu/llm.txt b/docs/i18n/hu/llm.txt index fdd9526279..1b941f1e5a 100644 --- a/docs/i18n/hu/llm.txt +++ b/docs/i18n/hu/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/id/llm.txt b/docs/i18n/id/llm.txt index 776304488c..e1b23c5e3d 100644 --- a/docs/i18n/id/llm.txt +++ b/docs/i18n/id/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/in/llm.txt b/docs/i18n/in/llm.txt index 2e0784f344..7713dacb68 100644 --- a/docs/i18n/in/llm.txt +++ b/docs/i18n/in/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/it/llm.txt b/docs/i18n/it/llm.txt index 160add875c..e0823ba499 100644 --- a/docs/i18n/it/llm.txt +++ b/docs/i18n/it/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/ja/llm.txt b/docs/i18n/ja/llm.txt index 7e3f75466f..5c1963195f 100644 --- a/docs/i18n/ja/llm.txt +++ b/docs/i18n/ja/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/ko/llm.txt b/docs/i18n/ko/llm.txt index 6cd010d0a4..2ae8fe4ec4 100644 --- a/docs/i18n/ko/llm.txt +++ b/docs/i18n/ko/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/mr/llm.txt b/docs/i18n/mr/llm.txt index 12129f663d..157eec643a 100644 --- a/docs/i18n/mr/llm.txt +++ b/docs/i18n/mr/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/ms/llm.txt b/docs/i18n/ms/llm.txt index 8c01bf3654..e26b195208 100644 --- a/docs/i18n/ms/llm.txt +++ b/docs/i18n/ms/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/nl/llm.txt b/docs/i18n/nl/llm.txt index 7fe980153e..67f935d590 100644 --- a/docs/i18n/nl/llm.txt +++ b/docs/i18n/nl/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/no/llm.txt b/docs/i18n/no/llm.txt index 32364510ee..e28dda1508 100644 --- a/docs/i18n/no/llm.txt +++ b/docs/i18n/no/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/phi/llm.txt b/docs/i18n/phi/llm.txt index 54595155ef..ed539c84be 100644 --- a/docs/i18n/phi/llm.txt +++ b/docs/i18n/phi/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/pl/llm.txt b/docs/i18n/pl/llm.txt index 18c1d5aeaf..f8665fa410 100644 --- a/docs/i18n/pl/llm.txt +++ b/docs/i18n/pl/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/pt-BR/llm.txt b/docs/i18n/pt-BR/llm.txt index 8dc803bdbe..c56d966794 100644 --- a/docs/i18n/pt-BR/llm.txt +++ b/docs/i18n/pt-BR/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/pt/llm.txt b/docs/i18n/pt/llm.txt index 0a841f4d7f..6e2aa2bb20 100644 --- a/docs/i18n/pt/llm.txt +++ b/docs/i18n/pt/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/ro/llm.txt b/docs/i18n/ro/llm.txt index 4461a57b48..4fac614baf 100644 --- a/docs/i18n/ro/llm.txt +++ b/docs/i18n/ro/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/ru/llm.txt b/docs/i18n/ru/llm.txt index e4b51b687b..9d522135b2 100644 --- a/docs/i18n/ru/llm.txt +++ b/docs/i18n/ru/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/sk/llm.txt b/docs/i18n/sk/llm.txt index 3783940896..df0dbd95a7 100644 --- a/docs/i18n/sk/llm.txt +++ b/docs/i18n/sk/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/sv/llm.txt b/docs/i18n/sv/llm.txt index 3e4eb1f5f4..59246e38bf 100644 --- a/docs/i18n/sv/llm.txt +++ b/docs/i18n/sv/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/sw/llm.txt b/docs/i18n/sw/llm.txt index ec134c100a..dbbf236c5d 100644 --- a/docs/i18n/sw/llm.txt +++ b/docs/i18n/sw/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/ta/llm.txt b/docs/i18n/ta/llm.txt index 64848422b9..842ca8c7ee 100644 --- a/docs/i18n/ta/llm.txt +++ b/docs/i18n/ta/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/te/llm.txt b/docs/i18n/te/llm.txt index ebb7d28a0c..5098dbc0ae 100644 --- a/docs/i18n/te/llm.txt +++ b/docs/i18n/te/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/th/llm.txt b/docs/i18n/th/llm.txt index dc01025526..f1251db7be 100644 --- a/docs/i18n/th/llm.txt +++ b/docs/i18n/th/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/tr/llm.txt b/docs/i18n/tr/llm.txt index 182af11a3b..ba729555c2 100644 --- a/docs/i18n/tr/llm.txt +++ b/docs/i18n/tr/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/uk-UA/llm.txt b/docs/i18n/uk-UA/llm.txt index bd5997d66a..33b12b870b 100644 --- a/docs/i18n/uk-UA/llm.txt +++ b/docs/i18n/uk-UA/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/ur/llm.txt b/docs/i18n/ur/llm.txt index 6d04724edb..bd5d5fdc83 100644 --- a/docs/i18n/ur/llm.txt +++ b/docs/i18n/ur/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/vi/llm.txt b/docs/i18n/vi/llm.txt index ff99a1050e..4b59fd5d3d 100644 --- a/docs/i18n/vi/llm.txt +++ b/docs/i18n/vi/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/zh-CN/llm.txt b/docs/i18n/zh-CN/llm.txt index 925f9e6184..122734bec7 100644 --- a/docs/i18n/zh-CN/llm.txt +++ b/docs/i18n/zh-CN/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/i18n/zh-TW/llm.txt b/docs/i18n/zh-TW/llm.txt index 1c95e25755..b1f841f8e9 100644 --- a/docs/i18n/zh-TW/llm.txt +++ b/docs/i18n/zh-TW/llm.txt @@ -4,7 +4,7 @@ --- -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -169,7 +169,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -479,7 +479,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/docs/providers/CURSOR-API-KEY-AND-CLI.md b/docs/providers/CURSOR-API-KEY-AND-CLI.md new file mode 100644 index 0000000000..53c0a85dfd --- /dev/null +++ b/docs/providers/CURSOR-API-KEY-AND-CLI.md @@ -0,0 +1,123 @@ +--- +title: "Cursor API provider and the Cursor CLI passthrough" +version: 3.8.50 +lastUpdated: 2026-08-19 +--- + +# Cursor API provider and the Cursor CLI passthrough + +Two ways to put Cursor behind OmniRoute without an IDE session: + +1. **`cursor-api` provider** (card "Cursor API", alias `cua`): an API-key + provider that holds a Cursor user API key (`crsr_…`, generated at + `https://cursor.com/dashboard/api`). Any OmniRoute client then reaches + Cursor models through `/v1/chat/completions` as `cursor-api/` or + `cua/`, with the usual quota, fallback and logging layers. The IDE + provider (`cursor`, OAuth/IDE session) is unchanged. +2. **Cursor CLI passthrough**: point the Cursor CLI (`agent`) at OmniRoute so + every RPC the CLI makes is authenticated with an OmniRoute API key, forwarded + to Cursor with a `cursor-api` connection's credential, and recorded in the + Logs page. + +## Why the key is exchanged + +`api2.cursor.sh` rejects a raw `crsr_…` key as a Bearer token (401). The Cursor +CLI first POSTs the key to `/auth/exchange_user_api_key` and receives a session +JWT that expires after one hour; the returned `refreshToken` carries the same +`exp`, so refreshing means re-exchanging the key. +`open-sse/services/cursorApiKeyAuth.ts` does that exchange, caches one session +token per key, re-exchanges five minutes before expiry and drops the cached +token when Cursor answers 401. `CursorExecutor` calls it right before opening +the upstream stream for `cursor-api` connections. + +## The `cursor-api` provider + +Registry: `open-sse/config/providers/registry/cursor/index.ts` +(`cursor_apiProvider`, `authType: "apikey"`, same `format`, `baseUrl` and +`models` as `cursor`). Catalog card: +`src/shared/constants/providers/apikey/specialty-media.ts`. Executor map: +`open-sse/executors/index.ts` (`"cursor-api"` / `cua` → +`new CursorExecutor("cursor-api")`). + +Dashboard: Providers → Cursor API → Add API key. + +REST: + +```bash +curl -sS -X POST http://localhost:20128/api/providers \ + -H "Content-Type: application/json" \ + -d '{"provider":"cursor-api","name":"cursor-api-key","apiKey":"crsr_…","priority":1}' +``` + +Then: + +```bash +curl -sS http://localhost:20128/v1/chat/completions \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{"model":"cursor-api/auto","messages":[{"role":"user","content":"say PONG"}]}' +``` + +Notes: + +- Model listing for `cursor-api` comes from the static Cursor registry (the + same list the IDE provider falls back to); no `cursor-agent` install is + needed on the OmniRoute host. +- `POST /api/providers/{id}/refresh-cursor` is for the `cursor` IDE provider + only; `cursor-api` connections have no IDE session to renew. + +## Cursor CLI passthrough + +Route: `src/app/api/cursor-cli/[...path]/route.ts` → +`open-sse/handlers/cursorCliProxy.ts`. The prefix `/api/cursor-cli/` is +registered in `src/shared/constants/publicApiRoutes.ts` because the handler +enforces its own authentication: + +| Path | Auth expected from the CLI | What OmniRoute does | +| ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `POST /auth/exchange_user_api_key` | `Bearer ` | Validates the key, mints a 1h HS256 JWT (signed with `JWT_SECRET`) and returns it | +| every other path (`/aiserver.v1.*`, `/agent.v1.AgentService/RunSSE`, `/aiserver.v1.BidiService/BidiAppend`, `/v1/traces`, …) | `Bearer ` | Verifies issuer/audience/expiry, picks an active `cursor-api` connection, swaps the Authorization header for the exchanged Cursor token and streams the reply back | + +The CLI decodes `exp` from whatever token it receives, so handing it an opaque +token makes it re-exchange before almost every request; the minted JWT avoids +that. A 401 from OmniRoute makes the CLI exchange again. + +### Setup + +1. Create an OmniRoute API key (Dashboard → API keys) and a `cursor-api` + connection. +2. Tell the CLI to use HTTP/1.1 for the agent stream. In + `~/.cursor/cli-config.json`: + + ```json + { "network": { "useHttp1ForAgent": true } } + ``` + + Without this the CLI opens the agent turn over HTTP/2 to a separately + configured agent host and only the control-plane RPCs go through the + endpoint. + +3. Run the CLI against OmniRoute: + + ```bash + export CURSOR_API_ENDPOINT=http://localhost:20128/api/cursor-cli + export CURSOR_API_KEY= + agent -p --trust "Reply with exactly OK" + ``` + +Every hop lands in Logs as provider `cursor-api`, request type `cursor-cli`, +path `/api/cursor-cli/`, attributed to the OmniRoute API key and the +connection that served it. + +### Failure modes + +| Situation | Response to the CLI | +| ------------------------------------------------ | --------------------------------------------- | +| Unknown OmniRoute key and `REQUIRE_API_KEY=true` | 401 `unauthenticated` on exchange | +| `REQUIRE_API_KEY=false` | anonymous session (mirrors `/v1/*` behaviour) | +| Expired / foreign / tampered session JWT | 401, the CLI re-exchanges | +| OmniRoute API key revoked after exchange | 401 on the next RPC | +| No active `cursor-api` connection | 503 `unavailable` | +| Cursor rejects the connection's key | 401 `unauthenticated`, cached session dropped | +| Upstream unreachable | 502 `unavailable` (sanitized message) | +| `JWT_SECRET` unset | 503 on exchange | diff --git a/docs/providers/meta.json b/docs/providers/meta.json index 82eec7eca7..fa6485dd57 100644 --- a/docs/providers/meta.json +++ b/docs/providers/meta.json @@ -7,6 +7,7 @@ "CHATGPT_WEB", "AGENTROUTER", "ZED-DOCKER", - "CURSOR-DOCKER" + "CURSOR-DOCKER", + "CURSOR-API-KEY-AND-CLI" ] } diff --git a/docs/reference/ENVIRONMENT.md b/docs/reference/ENVIRONMENT.md index ccb6a6981f..981cdc473b 100644 --- a/docs/reference/ENVIRONMENT.md +++ b/docs/reference/ENVIRONMENT.md @@ -95,6 +95,7 @@ OmniRoute uses **SQLite** (via `better-sqlite3`) for all persistence. These vari | `OMNIROUTE_CRYPT_KEY` | _(unset)_ | `src/lib/db/encryption.ts` | **Legacy alias** for `STORAGE_ENCRYPTION_KEY`. Accepted as a fallback when the primary variable is absent. | | `OMNIROUTE_API_KEY_BASE64` | _(unset)_ | `src/lib/db/encryption.ts` | **Legacy alias** (Base64-encoded form) accepted as a fallback. Decoded automatically before use. | | `OMNIROUTE_DB_HEALTHCHECK_INTERVAL_MS` | _(unset)_ | `src/lib/db/core.ts` | Override the periodic SQLite healthcheck interval (ms). When unset, defaults are derived from `NODE_ENV`. | +| `OMNIROUTE_WAL_TRUNCATE_INTERVAL_MS` | `21600000` (6h) | `src/lib/db/core.ts` | Override the periodic `wal_checkpoint(TRUNCATE)` interval (ms). Auto-checkpoint never shrinks the WAL file itself, and a long-running server never closes its DB. `0` disables. | | `OMNIROUTE_SKIP_DB_HEALTHCHECK` | `0` | `src/lib/db/core.ts`, `src/lib/db/healthCheck.ts` | Set to `1` to skip the DB healthcheck entirely on startup. Useful for short-lived tasks and integration tests. | | `OMNIROUTE_FORCE_DB_HEALTHCHECK` | `0` | `src/lib/db/core.ts` | Set to `1` to force the DB healthcheck loop on, even when it would normally be skipped (e.g., short-lived tasks). | | `OMNIROUTE_SKIP_POSTINSTALL` | `0` | `scripts/postinstall.mjs` | Set to `1` to skip the native-runtime warm-up during `npm install`. Useful in CI/headless installs where sqlite is already built. | diff --git a/docs/reference/PROVIDER_REFERENCE.md b/docs/reference/PROVIDER_REFERENCE.md index 13869aa651..64dc00960d 100644 --- a/docs/reference/PROVIDER_REFERENCE.md +++ b/docs/reference/PROVIDER_REFERENCE.md @@ -1,16 +1,16 @@ --- title: "Provider Reference" version: 3.8.50 -lastUpdated: 2026-08-18 +lastUpdated: 2026-08-19 --- # Provider Reference > **Auto-generated** from `src/shared/constants/providers.ts` — do not edit by hand. > Regenerate with: `npm run gen:provider-reference` -> **Last generated:** 2026-08-18 +> **Last generated:** 2026-08-19 -Total providers: **341**. See category breakdown below. +Total providers: **342**. See category breakdown below. ## Categories @@ -91,7 +91,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each | `chatgpt-web-codex` | `cgpt-codex` | ChatGPT Web (Codex) | Web cookie | [link](https://chatgpt.com) | Paste the full ChatGPT Cookie header. OmniRoute verifies it in an isolated headless browser profile. | native | | `claude-web` | `cw` | Claude Web | Web cookie | [link](https://claude.ai) | Paste your session cookie from claude.ai | none | | `conol-web` | `cnl` | Conol (Unofficial/Experimental) | Web cookie | [link](https://conol.ai) | Use browser sign-in, or paste the full Cookie header from conol.ai. The __Secure-better-auth.session_token cookie is required. | — | -| `copilot-m365-web` | `m365copilot` | Microsoft 365 Copilot (BizChat) | Web cookie | [link](https://m365.cloud.microsoft/chat) | Sign in at m365.cloud.microsoft/chat, then open DevTools → Network → filter 'WS' → click the Chathub WebSocket connection. Copy both the access_token query parameter AND the account-specific Chathub path segment from its request URL (wss://…/Chathub/?…&access_token=…). It is NOT an Authorization: Bearer header on an XHR/Fetch request. The token is short-lived; this is an unofficial integration. | — | +| `copilot-m365-web` | `m365copilot` | Microsoft 365 Copilot (BizChat) | Web cookie | [link](https://m365.cloud.microsoft/chat) | Sign in at m365.cloud.microsoft/chat, then open DevTools → Network → filter 'WS' → click the Chathub WebSocket connection. Copy both the access_token query parameter AND the account-specific Chathub path segment from its request URL (wss://…/Chathub/?…&access_token=…). It is NOT an Authorization: Bearer header on an XHR/Fetch request. The token is short-lived; this is an unofficial integration. Optional: store a refresh_token in providerSpecificData.refreshToken (any Microsoft device-code/refresh flow for the substrate.office.com/sydney scopes) and OmniRoute pre-flight-refreshes the access token itself — otherwise re-capture after every ~75 min expiry. | — | | `copilot-web` | `copilot` | Microsoft Copilot Web | Web cookie | [link](https://copilot.microsoft.com) | Paste the access_token from an authenticated copilot.microsoft.com request (DevTools → Network → Authorization), or export a HAR while logged in | — | | `deepseek-web` | `ds-web` | DeepSeek Web | Web cookie | [link](https://chat.deepseek.com) | Paste your userToken from chat.deepseek.com — DevTools → Application → Local Storage → userToken | emulated | | `doubao-web` | `db` | Dola Web (ByteDance) | Web cookie | [link](https://www.dola.com) | Paste the full Cookie header from www.dola.com. It should include sessionid, ttwid, and s_v_web_id. If s_v_web_id is unavailable, fp=verify_... from a chat/completion request URL can be used as a fallback. | — | @@ -120,7 +120,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each | `zai-web` | `zw` | Z.ai Web | Web cookie | [link](https://chat.z.ai) | Copy the "token" value from chat.z.ai → DevTools → Application → Local Storage. Do not copy cookies; OmniRoute handles the per-request CAPTCHA through its browser transport. | — | | `zenmux-free` | `zmf` | ZenMux Free (Web) | Web cookie | [link](https://zenmux.ai) | Login at zenmux.ai, then export all cookies using EditThisCookie or Cookie-Editor and paste the full Cookie header string here. Refresh every ~30 days. | — | -## API Key Providers (paid / paid-with-free-credits) (228) +## API Key Providers (paid / paid-with-free-credits) (229) | ID | Alias | Name | Tags | Website | Notes | |----|-------|------|------|---------|-------| @@ -169,6 +169,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each | `command-code` | `cmd` | Command Code | API key | [link](https://commandcode.ai/) | Use a Command Code API key. Requests are sent to Command Code's /alpha/generate endpoint. | | `coze` | `coze` | Coze | API key | [link](https://coze.com) | Get API key at coze.com/open/api | | `crof` | `crof` | CrofAI | API key | [link](https://crof.ai) | — | +| `cursor-api` | `cua` | Cursor API | API key | [link](https://cursor.com/dashboard/api) | Paste a Cursor user API key (crsr_...) from cursor.com/dashboard/api. OmniRoute exchanges it for a session token on demand; no IDE or cursor-agent install is needed. Usage bills to the Cursor plan that owns the key. | | `dahl` | `dahl` | Dahl | API key | [link](https://inference.dahl.global) | Click 'Add Account' to auto-generate a token, or add a manual API key. | | `databricks` | `databricks` | Databricks | API key, enterprise | [link](https://www.databricks.com) | — | | `datarobot` | `datarobot` | DataRobot | API key, enterprise | [link](https://docs.datarobot.com) | Use your DataRobot API token. Optional Base URL can be the account root (for LLM Gateway) or a deployment URL under /api/v2/deployments/. | @@ -323,7 +324,8 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each | `tinyfish` | `tf` | TinyFish Fetch | API key | [link](https://docs.tinyfish.ai/fetch-api) | X-API-Key from agent.tinyfish.ai/api-keys | | `together` | `together` | Together AI | API key, video | [link](https://www.together.ai) | — | | `tokenreply` | `tokenreply` | TokenReply | API key, aggregator | [link](https://www.tokenreply.com) | Free-tagged models have model- and campaign-specific daily limits; no fixed global free quota is published. | -| `tokenrouter` | `trk` | TokenRouter | API key | [link](https://tokenrouter.com) | Use your TokenRouter API key in Authorization: Bearer . Fully OpenAI-compatible. API base URL: https://api.tokenrouter.com/v1. | +| `tokenrouter` | `trk` | TokenRouter | API key | [link](https://tokenrouter.com) | Use your TokenRouter API key in Authorization: Bearer *** Fully OpenAI-compatible. API base URL: https://api.tokenrouter.com/v1. | +| `token-kiosk` | `tk` | Token Kiosk | API key | [link](https://agent-router.gaib.ai) | Use your Token Kiosk API key in Authorization: Bearer *** Fully OpenAI-compatible. API base URL: https://agent-router.gaib.ai/v1. | | `topaz` | `topaz` | Topaz | API key, image | [link](https://topazlabs.com) | — | | `typhoon` | `typhoon` | Typhoon | API key | [link](https://docs.opentyphoon.ai) | Free API key with a 5 req/s and 200 req/m rate limit. | | `udio` | `udio` | Udio | API key | [link](https://udio.com) | Paste session cookie from udio.com (Supabase auth) | diff --git a/docs/routing/AUTO-COMBO.md b/docs/routing/AUTO-COMBO.md index 7a0b387191..bad9aa43dd 100644 --- a/docs/routing/AUTO-COMBO.md +++ b/docs/routing/AUTO-COMBO.md @@ -159,6 +159,28 @@ enumerating every existing combo that shadows a model id, so operators who hit this by accident (rather than intentionally, per #6940) have a signal. The detection helper lives in `src/lib/combos/modelNameCollision.ts`. +## Calling a Custom Combo From a Client + +Persisted combos (Settings → Combos) are only used when the client sends the combo's **exact name** in the `model` field — there is no fuzzy or partial matching of the combo name, and no `auto/` prefix involved. Resolution order (`getComboForModel()` in `src/sse/services/model.ts`): + +1. exact combo-name match (`model: "my-combo"`), +2. `combo/` prefix (`model: "combo/my-combo"`), +3. model→combo glob mappings (`/api/model-combo-mappings`). + +```bash +curl -X POST http://localhost:20128/v1/chat/completions \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{"model":"my-combo","messages":[{"role":"user","content":"Hello"}]}' +``` + +Two common pitfalls: + +- **`auto` does not use your combos.** `auto`/`auto/*` builds its own zero-config candidate pool and only consults persisted combos if a combo is literally named `auto` (not recommended). To route through a combo, send its exact name — not `auto`. +- **`openrouter/auto` is a real paid OpenRouter product** ("Auto Best Available"), not an OmniRoute alias. It is the single static model entry of the OpenRouter registry (`open-sse/config/providers/registry/openrouter/index.ts`) and is billed separately. Use Settings → Routing → Hide paid models to exclude it from `auto` pools. + +See [#7992](https://github.com/diegosouzapw/OmniRoute/issues/7992) and [#7111](https://github.com/diegosouzapw/OmniRoute/issues/7111) for the original confusion this documents. + ## How It Works (Persisted Auto-Combos) The Auto-Combo Engine dynamically selects the best provider/model for each request using a **14-factor scoring function** (defined in `open-sse/services/autoCombo/scoring.ts` → `DEFAULT_WEIGHTS`). Weights form a normalized distribution (custom weights are renormalized by `normalizeScoringWeights()`). diff --git a/electron/main.js b/electron/main.js index f052188ff3..61f9e784d9 100644 --- a/electron/main.js +++ b/electron/main.js @@ -781,6 +781,14 @@ function startNextServer() { ...serverEnv, DATA_DIR: dataDir, PORT: String(serverPort), + // Pin the embedded server to loopback. Next.js standalone binds to + // `process.env.HOSTNAME || '0.0.0.0'`, and Windows always exports + // HOSTNAME as the machine name — which resolves to the LAN address, so + // the server listens only there and 127.0.0.1 stays closed. The renderer + // then fails to load `http://localhost:`, "ready-to-show" never + // fires, and the window (created with `show: false`) is never shown. + // Mirrors scripts/dev/run-next-playwright.mjs, which already pins this. + HOSTNAME: "127.0.0.1", NODE_ENV: "production", ELECTRON_RUN_AS_NODE: "1", NODE_PATH: resolveServerNodePath(serverEnv, resolvePackNodePaths(dataDir)), diff --git a/examples/quickstart/python_requests.py b/examples/quickstart/python_requests.py index ab838d8eb7..a27c7b38b0 100644 --- a/examples/quickstart/python_requests.py +++ b/examples/quickstart/python_requests.py @@ -26,3 +26,8 @@ data = { response = requests.post(API_URL, headers=headers, json=data) response.raise_for_status() print(response.json()["choices"][0]["message"]["content"]) + +# Fresh install, zero credentials — `auto` already works: +# curl http://localhost:20128/v1/chat/completions \ +# -H "Content-Type: application/json" \ +# -d '{"model":"auto","messages":[{"role":"user","content":"Hello!"}]}' diff --git a/llm.txt b/llm.txt index 92016efd1c..cc2d9d5aba 100644 --- a/llm.txt +++ b/llm.txt @@ -1,6 +1,6 @@ # OmniRoute -> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 341 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. +> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 342 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (109 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app. ## Overview @@ -165,7 +165,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo │ │ └── manager.ts # MITM proxy manager │ ├── shared/ # Shared utilities, components, and constants │ │ ├── components/ # Reusable UI components (Card, Badge, Button, Modal, Sidebar, ProviderIcon, etc.) -│ │ ├── constants/ # Provider definitions (341), model lists, pricing, routing strategies, MCP scopes +│ │ ├── constants/ # Provider definitions (342), model lists, pricing, routing strategies, MCP scopes │ │ ├── contracts/ # Shared API contracts │ │ ├── hooks/ # React hooks │ │ ├── middleware/ # Shared middleware utilities @@ -277,7 +277,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo ## Key Features (v3.8.50) ### Core Proxy -- **341 AI providers** with automatic format translation +- **342 AI providers** with automatic format translation - **Provider categories**: Free (90+ free tiers), OAuth, API Key, Self-Hosted, Custom (OpenAI/Anthropic-compatible) - **18 routing strategies**: priority, weighted, round-robin, fill-first, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, context-relay, fusion, pipeline - **4-tier fallback**: Subscription → API Key → Cheap → Free @@ -475,7 +475,7 @@ diagnostics) plus **memory**, **skill**, **agentSkill**, **githubSkill**, **pool ## v3.8.x Highlights -- **341-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add +- **342-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add - **19 routing strategies** — including `fusion` (parallel panel + judge synthesis), `pipeline`, `reset-aware`, `reset-window`, `headroom`, and `context-relay` - **14-factor Auto-Combo scoring** with bandit exploration and progressive cooldown - **MCP server expanded to 109 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules) diff --git a/open-sse/config/codexClient.ts b/open-sse/config/codexClient.ts index 0cb1b05772..5c71e931a5 100644 --- a/open-sse/config/codexClient.ts +++ b/open-sse/config/codexClient.ts @@ -1,9 +1,13 @@ import { + CODEX_CLI_RS_ORIGINATOR, DEFAULT_CODEX_CLIENT_VERSION, getCodexCliRsHeaders as buildCodexCliRsHeaders, } from "@/shared/constants/codexClient"; -export { DEFAULT_CODEX_CLIENT_VERSION } from "@/shared/constants/codexClient"; +export { + DEFAULT_CODEX_CLIENT_VERSION, + CODEX_CLI_RS_ORIGINATOR, +} from "@/shared/constants/codexClient"; const DEFAULT_CODEX_USER_AGENT_PLATFORM = "Windows 10.0.26200"; const DEFAULT_CODEX_USER_AGENT_ARCH = "x64"; const CODEX_VERSION_OVERRIDE_ENV = "CODEX_CLIENT_VERSION"; @@ -51,6 +55,35 @@ export function getCodexCliRsHeaders(): Record { return buildCodexCliRsHeaders(getCodexClientVersion()); } +/** + * Identity for the credential face (auth.openai.com: token exchange / refresh). + * The real Codex client sends only `originator` + `User-Agent` on that face + * (codex-rs login/default_client.rs default_headers()); the `Version` header + * gate exists only on the chatgpt.com/backend-api inference face, so it is + * deliberately omitted here. Mirrors sub2api v0.1.178 + * ApplyCodexCanonicalAuthIdentity. + */ +export function getCodexAuthIdentityHeaders(): Record { + return { + "User-Agent": getCodexUserAgent(), + originator: CODEX_CLI_RS_ORIGINATOR, + }; +} + +/** + * Canonical Codex CLI identity for server-initiated calls against the + * chatgpt.com/backend-api face that are not tied to one end-client request + * (usage / quota / models manifest / reset-credits). Same UA/version chain as + * inference so these calls do not show up upstream as anonymous half-identities. + */ +export function getCodexBackendIdentityHeaders(): Record { + return { + "User-Agent": getCodexUserAgent(), + originator: CODEX_CLI_RS_ORIGINATOR, + Version: getCodexClientVersion(), + }; +} + export function normalizeCodexSessionId(value: unknown): string | null { if (typeof value !== "string") return null; const normalized = value.trim(); diff --git a/open-sse/config/codexIdentity.ts b/open-sse/config/codexIdentity.ts index bc45fa1cf6..a081c5402b 100644 --- a/open-sse/config/codexIdentity.ts +++ b/open-sse/config/codexIdentity.ts @@ -1,15 +1,30 @@ import { createHash, randomUUID } from "node:crypto"; import { normalizeCodexSessionId } from "./codexClient.ts"; +import { isCrossAccountCodexTurnState, readCodexTurnStateHeader } from "./codexTurnState.ts"; const CODEX_INSTALLATION_SALT = "omniroute-codex-installation"; const CODEX_SESSION_SEED_PREFIX = "omniroute:codex-session-id:v1:"; const CODEX_THREAD_SEED_PREFIX = "omniroute:codex-thread-id:v1:"; +// v2 derivations are keyed by the persisted per-connection random seed +// (codexFingerprintSeed) instead of the connection-id chain, mirroring +// sub2api v0.1.178 (#5696): deterministic derivation stays stable, but the +// seed is generated per connection so identities never collide across +// deployments and survive connection export/import. +const CODEX_INSTALLATION_SEED_PREFIX_V2 = "omniroute:codex-installation:v2:"; +const CODEX_SESSION_SEED_PREFIX_V2 = "omniroute:codex-session-id:v2:"; +const CODEX_THREAD_SEED_PREFIX_V2 = "omniroute:codex-thread-id:v2:"; const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; export const CODEX_FINGERPRINT_MODES = ["off", "device", "session", "full"] as const; export type CodexFingerprintMode = (typeof CODEX_FINGERPRINT_MODES)[number]; export const CODEX_FINGERPRINT_MODE_KEY = "codexFingerprintMode"; +/** + * System-managed per-connection random seed used as the fingerprint + * derivation source. Never sent upstream, stripped from API responses, and + * preserved across connection updates (sub2api `codex_fingerprint_seed`). + */ +export const CODEX_FINGERPRINT_SEED_KEY = "codexFingerprintSeed"; export type CodexClientIdentity = { mode: CodexFingerprintMode; @@ -72,6 +87,61 @@ function accountSeed( ); } +/** The persisted system-managed random seed, when present and a valid UUID. */ +export function getCodexFingerprintSeed( + providerSpecificData?: Record | null +): string | null { + return normalizeUuid(providerSpecificData?.[CODEX_FINGERPRINT_SEED_KEY]); +} + +/** Modes that rewrite account-scoped identifiers and therefore need a stable seed. */ +export function codexFingerprintModeRequiresSeed(mode: CodexFingerprintMode): boolean { + return mode === "device" || mode === "session" || mode === "full"; +} + +/** + * Ensure a Codex OAuth connection carries a persisted fingerprint seed when its + * convergence mode derives account-scoped identifiers. Called at connection + * create/update time (the persistence layer owns the write); the request path + * only ever READS the seed, so an identity never rotates mid-flight. + * + * Semantics mirror sub2api v0.1.178 `prepareCodexFingerprintExtraFor{Create,Update}`: + * - the key is system-managed: any client-supplied value is stripped first; + * - an existing valid seed is ALWAYS carried forward (even when the new mode + * is `off` — it stays dormant, ready if convergence is re-enabled later); + * - otherwise a fresh seed is created only when the mode requires one + * (device/session/full; the OmniRoute default is session). + * + * Returns the (possibly new) providerSpecificData, or undefined when there is + * nothing to store. Pre-seed connections keep their legacy connection-id + * derived identity until the next save — one deliberate rotation, same as + * sub2api's migration-225 backfill. + */ +export function ensureCodexFingerprintSeed( + providerSpecificData?: Record | null, + credentials?: { accessToken?: unknown; refreshToken?: unknown } | null, + existingProviderSpecificData?: Record | null +): Record | undefined { + const psd: Record = { ...(providerSpecificData || {}) }; + // System-managed key: never trust an inbound value, regardless of auth type. + delete psd[CODEX_FINGERPRINT_SEED_KEY]; + if (!isCodexOAuthCredentials(credentials)) { + return Object.keys(psd).length > 0 ? psd : undefined; + } + + const existingSeed = getCodexFingerprintSeed(existingProviderSpecificData); + if (existingSeed) { + psd[CODEX_FINGERPRINT_SEED_KEY] = existingSeed; + return psd; + } + const mode = getCodexFingerprintMode(psd, true); + if (codexFingerprintModeRequiresSeed(mode)) { + psd[CODEX_FINGERPRINT_SEED_KEY] = randomUUID(); + return psd; + } + return Object.keys(psd).length > 0 ? psd : undefined; +} + function readNamedHeader( headers: Headers | Record | null | undefined, name: string @@ -120,6 +190,11 @@ export function getCodexInstallationId( const explicit = normalizeUuid(providerSpecificData?.codexInstallationId); if (explicit) return explicit; + const persistedSeed = getCodexFingerprintSeed(providerSpecificData); + if (persistedSeed) { + return deriveStableUUIDv4(`${CODEX_INSTALLATION_SEED_PREFIX_V2}${persistedSeed}`); + } + const legacyStableSource = nonEmptyString(providerSpecificData?.workspaceId) || nonEmptyString(providerSpecificData?.accountId) || @@ -137,6 +212,10 @@ export function getCodexConvergedSessionId( providerSpecificData?: Record | null, accountKey?: string | null ): string { + const persistedSeed = getCodexFingerprintSeed(providerSpecificData); + if (persistedSeed) { + return deriveStableUUIDv4(`${CODEX_SESSION_SEED_PREFIX_V2}${persistedSeed}`); + } return deriveStableUUIDv4( `${CODEX_SESSION_SEED_PREFIX}${accountSeed(providerSpecificData, accountKey)}` ); @@ -148,6 +227,10 @@ export function getCodexConvergedThreadId( accountKey?: string | null ): string { if (!nonEmptyString(clientSessionId)) return ""; + const persistedSeed = getCodexFingerprintSeed(providerSpecificData); + if (persistedSeed) { + return deriveStableUUIDv4(`${CODEX_THREAD_SEED_PREFIX_V2}${persistedSeed}:${clientSessionId}`); + } return deriveStableUUIDv4( `${CODEX_THREAD_SEED_PREFIX}${accountSeed(providerSpecificData, accountKey)}:${clientSessionId}` ); @@ -163,6 +246,26 @@ export function getCodexClientSessionId( ); } +/** + * Decide what to do with the client's `x-codex-turn-state` echo for the + * account about to serve this request. The blob is minted per account by the + * upstream; replaying another account's blob after failover is a proxy-only + * contradiction, so a known cross-account echo is stripped. Same-account or + * unknown provenance passes through unchanged (strip only, never inject). + * Independent of the fingerprint-convergence mode — account consistency also + * applies to explicit `off` / passthrough. + */ +export function resolveCodexTurnStateEcho( + clientHeaders?: Headers | Record | null, + accountKey?: string | null +): string | null { + const value = readCodexTurnStateHeader(clientHeaders); + if (!value) return null; + const sessionId = getCodexClientSessionId(clientHeaders); + if (sessionId && isCrossAccountCodexTurnState(sessionId, accountKey)) return null; + return value; +} + /** * One identity object for every carrier in one upstream turn. * accountKey may be the OmniRoute connection id; it is never sent upstream. @@ -284,13 +387,19 @@ export function withCodexFingerprintCredentials(); +let turnStateWrites = 0; + +function normalizeAccountKey(accountKey: unknown): string | null { + if (typeof accountKey !== "string") return null; + const trimmed = accountKey.trim(); + return trimmed || null; +} + +/** + * Read the turn-state blob from a headers bag (Headers instance or a plain + * record with arbitrary casing). Returns null when absent/blank. + */ +export function readCodexTurnStateHeader( + headers: Headers | Record | null | undefined +): string | null { + if (!headers) return null; + if (headers instanceof Headers) { + const value = headers.get(CODEX_TURN_STATE_HEADER); + return typeof value === "string" && value.trim() ? value.trim() : null; + } + if (typeof headers === "object") { + for (const [key, value] of Object.entries(headers)) { + if ( + key.toLowerCase() === CODEX_TURN_STATE_HEADER && + typeof value === "string" && + value.trim() + ) { + return value.trim(); + } + } + } + return null; +} + +function sweepExpiredTurnStateOrigins(now: number): void { + for (const [key, origin] of turnStateOrigins) { + if (origin.expiresAt <= now) { + turnStateOrigins.delete(key); + } + } +} + +/** + * Record that `accountKey` minted the turn-state blob this downstream session + * just received. Must only be called at the response commit point — when the + * header is actually written to the client. Recording earlier (e.g. for an + * attempt later discarded by failover) would poison the table and make the + * guard strip the NEXT account's legitimate echo. + */ +export function noteCodexTurnStateProvenance( + clientSessionId: string | null | undefined, + accountKey: unknown, + nowMs?: number +): void { + const sessionId = typeof clientSessionId === "string" ? clientSessionId.trim() : ""; + const account = normalizeAccountKey(accountKey); + if (!sessionId || !account) return; + + const now = typeof nowMs === "number" ? nowMs : Date.now(); + turnStateOrigins.set(sessionId, { + accountKey: account, + expiresAt: now + CODEX_TURN_STATE_TTL_MS, + }); + + turnStateWrites += 1; + if (turnStateWrites % CODEX_TURN_STATE_SWEEP_EVERY_WRITES === 0) { + sweepExpiredTurnStateOrigins(now); + } +} + +/** + * Outbound guard: true when the echoed blob is KNOWN to have been minted by a + * different account and must be stripped before going upstream. Same-account + * or unknown provenance passes through unchanged — stripping only, never + * injection (clients that cannot echo are the Claude bridge's concern, not + * this module's). + */ +export function isCrossAccountCodexTurnState( + clientSessionId: string | null | undefined, + accountKey: unknown, + nowMs?: number +): boolean { + const sessionId = typeof clientSessionId === "string" ? clientSessionId.trim() : ""; + const account = normalizeAccountKey(accountKey); + if (!sessionId || !account) return false; + + const origin = turnStateOrigins.get(sessionId); + if (!origin) return false; + const now = typeof nowMs === "number" ? nowMs : Date.now(); + if (origin.expiresAt <= now) { + turnStateOrigins.delete(sessionId); + return false; + } + return origin.accountKey !== account; +} + +/** Test hook: forget all provenance records and reset the sweep counter. */ +export function __resetCodexTurnStateOriginsForTesting(): void { + turnStateOrigins.clear(); + turnStateWrites = 0; +} diff --git a/open-sse/config/providers/index.ts b/open-sse/config/providers/index.ts index 01395e7dd8..34189e0d00 100644 --- a/open-sse/config/providers/index.ts +++ b/open-sse/config/providers/index.ts @@ -65,7 +65,7 @@ import { api_airforceProvider } from "./registry/api-airforce/index.ts"; import { mistralProvider } from "./registry/mistral/index.ts"; import { togetherProvider } from "./registry/together/index.ts"; import { cohereProvider } from "./registry/cohere/index.ts"; -import { cursorProvider } from "./registry/cursor/index.ts"; +import { cursorProvider, cursor_apiProvider } from "./registry/cursor/index.ts"; import { volcengineProvider } from "./registry/volcengine/index.ts"; import { hackclubProvider } from "./registry/hackclub/index.ts"; import { freetheaiProvider } from "./registry/freetheai/index.ts"; @@ -213,6 +213,7 @@ import { kiroProvider } from "./registry/kiro/index.ts"; import { openadapterProvider } from "./registry/openadapter/index.ts"; import { ditProvider } from "./registry/dit/index.ts"; import { tokenrouterProvider } from "./registry/tokenrouter/index.ts"; +import { token_kioskProvider } from "./registry/token-kiosk/index.ts"; import { grok_cliProvider } from "./registry/grok-cli/index.ts"; import { codebuddy_cnProvider } from "./registry/codebuddy-cn/index.ts"; import { pioneerProvider } from "./registry/pioneer/index.ts"; @@ -326,6 +327,7 @@ export const REGISTRY: Record = { together: togetherProvider, cohere: cohereProvider, cursor: cursorProvider, + "cursor-api": cursor_apiProvider, volcengine: volcengineProvider, hackclub: hackclubProvider, freetheai: freetheaiProvider, @@ -475,6 +477,7 @@ export const REGISTRY: Record = { openadapter: openadapterProvider, dit: ditProvider, tokenrouter: tokenrouterProvider, + "token-kiosk": token_kioskProvider, "grok-cli": grok_cliProvider, "codebuddy-cn": codebuddy_cnProvider, pioneer: pioneerProvider, diff --git a/open-sse/config/providers/registry/cursor/index.ts b/open-sse/config/providers/registry/cursor/index.ts index 0e167d39bb..1bb6d02b21 100644 --- a/open-sse/config/providers/registry/cursor/index.ts +++ b/open-sse/config/providers/registry/cursor/index.ts @@ -156,3 +156,29 @@ export const cursorProvider: RegistryEntry = { { id: "kimi-k2.7-code", name: "Kimi K2.7 Code" }, ], }; + +/** + * API-key variant of the Cursor provider. + * + * Same wire protocol, executor and catalog as `cursor`, but the connection + * holds a Cursor user API key (`crsr_…`, cursor.com/dashboard/api) instead of + * an IDE/OAuth session. The executor exchanges that key for a session token + * on demand (open-sse/services/cursorApiKeyAuth.ts), so no cursor-agent or + * IDE install is needed on the OmniRoute host. Kept as a distinct backend ID + * so API-key and IDE-session connections never share renewal, quota or + * dashboard semantics. + */ +export const cursor_apiProvider: RegistryEntry = { + id: "cursor-api", + alias: "cua", + format: cursorProvider.format, + executor: "cursor-api", + baseUrl: cursorProvider.baseUrl, + chatPath: cursorProvider.chatPath, + authType: "apikey", + authHeader: "bearer", + defaultContextLength: cursorProvider.defaultContextLength, + headers: getCursorRegistryHeaders(), + clientVersion: CURSOR_REGISTRY_VERSION, + models: cursorProvider.models, +}; diff --git a/open-sse/config/providers/registry/sensenova/index.ts b/open-sse/config/providers/registry/sensenova/index.ts index 37e95acc32..2e8b5822f9 100644 --- a/open-sse/config/providers/registry/sensenova/index.ts +++ b/open-sse/config/providers/registry/sensenova/index.ts @@ -27,6 +27,8 @@ export const sensenovaProvider: RegistryEntry = { contextLength: 1048576, maxOutputTokens: 65536, supportsReasoning: true, + supportedThinkingEfforts: ["none", "low", "medium", "high", "xhigh"], + supportsXHighEffort: true, interleavedField: "reasoning_content", }, { diff --git a/open-sse/config/providers/registry/token-kiosk/index.ts b/open-sse/config/providers/registry/token-kiosk/index.ts new file mode 100644 index 0000000000..319747828c --- /dev/null +++ b/open-sse/config/providers/registry/token-kiosk/index.ts @@ -0,0 +1,20 @@ +import type { RegistryEntry } from "../../shared.ts"; + +export const token_kioskProvider: RegistryEntry = { + id: "token-kiosk", + alias: "tk", + format: "openai", + executor: "default", + baseUrl: "https://agent-router.gaib.ai/v1/chat/completions", + modelsUrl: "https://agent-router.gaib.ai/v1/models", + authType: "apikey", + authHeader: "bearer", + defaultContextLength: 128000, + models: [ + { id: "claude-3-5-sonnet", name: "Claude 3.5 Sonnet (Token Kiosk)", contextLength: 200000, toolCalling: true, supportsVision: true }, + { id: "deepseek-v3", name: "DeepSeek V3 (Token Kiosk)", contextLength: 64000, toolCalling: true }, + { id: "deepseek-r1", name: "DeepSeek R1 (Token Kiosk)", contextLength: 64000, toolCalling: true, supportsReasoning: true }, + { id: "kimi-k1.5", name: "Kimi K1.5 (Token Kiosk)", contextLength: 128000, toolCalling: true }, + { id: "minimax-m6", name: "MiniMax M6 (Token Kiosk)", contextLength: 128000, toolCalling: true }, + ], +}; diff --git a/open-sse/executors/base/reasoningEffort.ts b/open-sse/executors/base/reasoningEffort.ts index f3d138bb79..9b8ffb1da0 100644 --- a/open-sse/executors/base/reasoningEffort.ts +++ b/open-sse/executors/base/reasoningEffort.ts @@ -6,6 +6,7 @@ import { supportsClaudeMaxEffort, supportsXHighEffort, getProviderModel, + getProviderModels, } from "../../config/providerModels.ts"; /** @@ -351,6 +352,31 @@ export function sanitizeReasoningEffortForProvider( // new models from being unusable for weeks until they're whitelisted (#8057). if (effortStr === "max") { if (supportsMax) return body; // explicitly known to accept max + + // A model that explicitly advertises its accepted tiers is safe to normalize. + // Keep the default pass-through for absent metadata: an unlisted model might + // support literal `max`, and #8057 deliberately avoids blocking such models. + const providerModelId = modelStr.startsWith(`${provider}/`) + ? modelStr.slice(provider.length + 1) + : modelStr; + // Do not fall back to a globally registered model here. Identical ids can + // have different upstream contracts across providers (for example, OpenCode + // and SenseNova both expose deepseek-v4-flash with different max support). + const explicitEfforts = getProviderModels(provider).find( + (entry) => entry.id === providerModelId || entry.aliases?.includes(providerModelId) + )?.supportedThinkingEfforts; + const maxFallback = + Array.isArray(explicitEfforts) && !explicitEfforts.includes("max") + ? ["xhigh", "high", "medium", "low"].find((tier) => explicitEfforts.includes(tier)) + : undefined; + if (maxFallback) { + log?.info?.( + "REASONING_SANITIZE", + `${provider}/${modelStr}: downgraded reasoning_effort max → ${maxFallback} (explicit model capability)` + ); + return writeEffortValue(b, maxFallback, c); + } + if (!supportsXHigh) { // Model is explicitly flagged as rejecting xhigh (and not in supportsMax) — // it likely only accepts standard tiers. Degrade to its highest: high. @@ -360,7 +386,6 @@ export function sanitizeReasoningEffortForProvider( ); return writeEffortValue(b, "high", c); } - // Default: pass max through unchanged — trust the upstream return body; } diff --git a/open-sse/executors/codex.ts b/open-sse/executors/codex.ts index 93e5a2fe16..d73d520650 100644 --- a/open-sse/executors/codex.ts +++ b/open-sse/executors/codex.ts @@ -20,6 +20,7 @@ import { import { FETCH_BODY_TIMEOUT_MS, HTTP_STATUS, PROVIDERS } from "../config/constants.ts"; import { readCodexPeekChunk, buildCodexTimeoutSafePassthroughBody } from "./codex/bodyTimeout.ts"; import { + CODEX_CLI_RS_ORIGINATOR, getCodexClientVersion, getCodexUserAgent, normalizeCodexSessionId, @@ -225,7 +226,6 @@ function convertSystemToDeveloperRole(body: Record): void { } } - function stripOrphanedCodexFunctionCallOutputs(body: Record): void { if (!Array.isArray(body.input)) return; const input = body.input; @@ -1045,10 +1045,11 @@ export class CodexExecutor extends BaseExecutor { CodexClientIdentity | null | undefined; const originalIdentityHeaders = credentials?.providerSpecificData ?.codexOriginalIdentityHeaders as Record | null | undefined; + const turnStateEcho = credentials?.providerSpecificData?.codexTurnStateEcho; // Originator header — identifies the client type to the Codex backend. // Ref: openai/codex login/src/auth/default_client.rs DEFAULT_ORIGINATOR = "codex_cli_rs" - headers["originator"] = "codex_cli_rs"; + headers["originator"] = CODEX_CLI_RS_ORIGINATOR; // session_id header — enables prompt cache affinity on the Codex backend. // The official Codex client sets this to conversation_id (a stable UUID per session). @@ -1060,6 +1061,13 @@ export class CodexExecutor extends BaseExecutor { applyCodexOriginalIdentityHeaders(headers, originalIdentityHeaders); applyCodexClientIdentityHeaders(headers, clientIdentity); + // x-codex-turn-state: forward the client's echo when the provenance guard + // (in withCodexFingerprintCredentials) cleared it as same-account. The + // blob is account-bound; a stripped (absent) value must stay absent. + if (typeof turnStateEcho === "string" && turnStateEcho) { + headers["x-codex-turn-state"] = turnStateEcho; + } + return headers; } diff --git a/open-sse/executors/copilot-m365-connection.ts b/open-sse/executors/copilot-m365-connection.ts index 0c5303c250..d5f6d80c6c 100644 --- a/open-sse/executors/copilot-m365-connection.ts +++ b/open-sse/executors/copilot-m365-connection.ts @@ -160,7 +160,16 @@ export function resolveConnectionParams( const psd = (credentials?.providerSpecificData ?? {}) as JsonRecord; const parsedApiKey = typeof credentials?.apiKey === "string" ? parsePastedCredential(credentials.apiKey) : {}; + // A JWT in credentials.accessToken (3 dot-separated parts — the individual-tier + // token is an opaque JWE with 5) is the freshest copy: the executor refreshes it + // in place before resolving params, and the framework mutates it after a refresh. + const credentialsJwt = + typeof credentials?.accessToken === "string" && + credentials.accessToken.split(".").length === 3 + ? credentials.accessToken + : ""; const accessToken = + credentialsJwt || parsedApiKey.accessToken || (typeof credentials?.apiKey === "string" && credentials.apiKey && @@ -254,6 +263,135 @@ export function redactWsUrl(wsUrl: string): string { return wsUrl.replace(/access_token=[^&]*/i, "access_token=REDACTED"); } +// ── OAuth refresh support (#10718 — client ids observed in the browser token +// and M365-Copilot2API) ──────────────────────────────────────────────────── +// +// The browser-issued access_token lives ~75 minutes. These helpers redeem a +// stored refresh_token at the Microsoft identity platform (same public client +// the m365.cloud.microsoft web app uses) so the connection self-heals instead +// of requiring a fresh DevTools capture after every expiry. + +/** Public client id observed in both the browser token and M365-Copilot2API. */ +export const M365_OAUTH_CLIENT_ID = "c0ab8ce9-e9a0-42e7-b064-33d422df41f1"; + +export const M365_OAUTH_SCOPE = + "openid profile offline_access https://substrate.office.com/sydney/M365Chat.Read " + + "https://substrate.office.com/sydney/sydney.readwrite"; + +/** Refresh lead time — refresh when the current token has less than this left. */ +export const M365_REFRESH_LEAD_MS = 5 * 60 * 1000; + +type MinimalLog = { + info?: (tag: string, message: string) => void; + warn?: (tag: string, message: string) => void; +}; + +/** Decode a JWT payload WITHOUT verification — exp/tid are routing hints, never authz. */ +export function decodeJwtClaims( + token: string +): { exp?: number; tid?: string; oid?: string } | null { + try { + const parts = token.split("."); + if (parts.length !== 3) return null; + const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8")); + return payload && typeof payload === "object" ? payload : null; + } catch { + return null; + } +} + +/** True when the token is unreadable, already expired, or inside the refresh lead window. */ +export function tokenNeedsRefresh(token: string, leadMs = M365_REFRESH_LEAD_MS): boolean { + const claims = decodeJwtClaims(token); + if (!claims?.exp) return true; + return claims.exp * 1000 <= Date.now() + leadMs; +} + +/** The freshest readable access token for a connection (JWT column → apiKey → psd). */ +export function currentM365AccessToken( + credentials: ProviderCredentials | undefined +): string { + if ( + typeof credentials?.accessToken === "string" && + credentials.accessToken.split(".").length === 3 + ) { + return credentials.accessToken; + } + if (typeof credentials?.apiKey === "string") { + const parsed = parsePastedCredential(credentials.apiKey); + if (parsed.accessToken && parsed.accessToken.split(".").length === 3) return parsed.accessToken; + // Opaque (JWE) individual-tier token — still a usable credential, just not refreshable. + return parsed.accessToken || ""; + } + const psd = (credentials?.providerSpecificData ?? {}) as JsonRecord; + if (typeof psd.accessToken === "string") return psd.accessToken; + if (typeof psd.access_token === "string") return psd.access_token; + return ""; +} + +/** The chathub path (`@`) from wherever it is stored. */ +export function currentM365ChathubPath(credentials: ProviderCredentials | undefined): string { + const psd = (credentials?.providerSpecificData ?? {}) as JsonRecord; + return ( + (typeof credentials?.apiKey === "string" + ? parsePastedCredential(credentials.apiKey).chathubPath + : "") || + (typeof psd.chathubPath === "string" && psd.chathubPath) || + (typeof psd.userTenant === "string" && psd.userTenant) || + "" + ); +} + +export interface M365RefreshResult { + accessToken: string; + refreshToken?: string; + expiresIn?: number; +} + +/** + * Redeem the refresh_token (public client — no secret). MS may rotate the + * refresh_token; callers MUST persist the returned one when present or the + * token family dies after the first refresh. + */ +export async function refreshM365AccessToken( + refreshToken: string, + tid: string, + log?: MinimalLog +): Promise { + const endpoint = `https://login.microsoftonline.com/${tid || "common"}/oauth2/v2.0/token`; + try { + const res = await fetch(endpoint, { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Accept: "application/json", + }, + body: new URLSearchParams({ + client_id: M365_OAUTH_CLIENT_ID, + grant_type: "refresh_token", + refresh_token: refreshToken, + scope: M365_OAUTH_SCOPE, + }), + }); + const data = (await res.json().catch(() => ({}))) as Record; + if (!res.ok || typeof data.access_token !== "string") { + const error = typeof data.error === "string" ? data.error : `HTTP ${res.status}`; + log?.warn?.("M365_TOKEN", `refresh_token grant failed: ${error}`); + return { error }; + } + log?.info?.("M365_TOKEN", "access token refreshed via refresh_token grant"); + return { + accessToken: data.access_token, + refreshToken: typeof data.refresh_token === "string" ? data.refresh_token : undefined, + expiresIn: typeof data.expires_in === "number" ? data.expires_in : undefined, + }; + } catch (e) { + const error = e instanceof Error ? e.message : String(e); + log?.warn?.("M365_TOKEN", `refresh request failed: ${error}`); + return { error }; + } +} + /** Flatten OpenAI messages into a single prompt (system instructions prepended). */ export function buildPrompt(body: JsonRecord | undefined): string { const messages = (body?.messages as Array) || []; diff --git a/open-sse/executors/copilot-m365-frames.ts b/open-sse/executors/copilot-m365-frames.ts index add2716ee0..c8c6dee7be 100644 --- a/open-sse/executors/copilot-m365-frames.ts +++ b/open-sse/executors/copilot-m365-frames.ts @@ -11,7 +11,9 @@ * Protocol (from @skyzea1's #4042 capture): * - JSON messages terminated with the SignalR record separator `\x1e`. * - Handshake: → {"protocol":"json","version":1} ← {} → {"type":6} - * - Send: type:4 invocation to target "chat" with arguments[0] = { message, ... } + * - Send: type:4 invocation to target "chat" with arguments[0] = { message, ... }, + * immediately followed by a type:1 target:"Metrics" frame in the SAME socket + * write (#10718 — an invocation without its Metrics pair is silently dropped). * - Stream: type:1 target:"update" deltas (bot text at arguments[0].messages[].text, * accumulated — NOT incremental) → isLastUpdate:true → type:2 final → type:3 completion. */ @@ -25,19 +27,18 @@ export const HANDSHAKE_REQUEST = { protocol: "json", version: 1 } as const; /** SignalR keepalive ping frame. */ export const KEEPALIVE_PING = { type: 6 } as const; -/** Allowed message types observed in the individual M365 send frame. */ +/** + * Allowed message types observed in the 2026-08 recapture of the working + * `m365.cloud.microsoft/chat` client (#10718). The old 11-entry list is no longer + * seen on the wire — the stale shape gets closed immediately after the type:4. + */ export const ALLOWED_MESSAGE_TYPES = [ "Chat", "Suggestion", - "InternalSearchQuery", "Disengaged", - "InternalLoaderMessage", "Progress", - "GeneratedCode", - "RenderCardRequest", - "AdsQuery", - "SemanticSerp", - "GenerateContentQuery", + "EndOfRequest", + "InternalLoaderMessage", ] as const; /** @@ -74,22 +75,20 @@ export const M365_ENTERPRISE_EXTRA_MESSAGE_TYPES = [ "SwitchRespondingEndpoint", ] as const; +/** + * Individual / EDU option sets from the 2026-08 recapture (#10718) — 14 entries. + * The previous 25-entry consumer/MSA set (enable_msa_user, pdnascan, cwc_code_*, + * …) is no longer observed on the wire and belongs to the shape the substrate + * now drops silently. + */ export const M365_DEFAULT_OPTION_SETS = [ "search_result_progress_messages_with_search_queries", "update_textdoc_response_after_streaming", "deepleo_networking_timeout_10minutes_canmore", "cwc_flux_image", - "cwc_code_interpreter", - "cwc_code_interpreter_amsfix", - "enable_msa_user", - "cwcgptv", + "cwcfluxgptv", "flux_v3_gptv_enable_upload_multi_image_in_turn_wo_ch", "gptvnorm2048", - "pdnascan", - "cwc_code_interpreter_citation_fix", - "code_interpreter_interactive_charts", - "cwc_code_interpreter_interactive_charts_inline_image", - "code_interpreter_matplotlib_patching", "cwc_fileupload_odb", "update_memory_plugin", "add_custom_instructions", @@ -97,9 +96,6 @@ export const M365_DEFAULT_OPTION_SETS = [ "flux_v3_progress_messages", "enable_batch_token_processing", "enable_gg_gpt", - "flux_v3_image_gen_enable_non_watermarked_storage", - "flux_v3_image_gen_enable_story", - "rich_responses", ] as const; /** Append the record separator to a JSON-serializable frame. */ @@ -117,6 +113,32 @@ export function keepaliveFrame(): string { return encodeFrame(KEEPALIVE_PING); } +/** + * #10718 — the browser follows the type:4 chat invocation with this type:1 + * target:"Metrics" frame in the SAME socket write. Sending the invocation alone + * gets it silently ignored (no update frames at all), so the executor must + * concatenate `metricsFrame()` onto the invocation payload. + */ +export const CHAT_METRICS_FRAME = { + arguments: [ + { + Timestamps: { + ConnectionEstablished: "", + ConnectionStart: "", + UserInputStart: "", + UserInputSubmit: "", + }, + }, + ], + target: "Metrics", + type: 1, +} as const; + +/** Serialized Metrics follow-up frame (see {@link CHAT_METRICS_FRAME}). */ +export function metricsFrame(): string { + return encodeFrame(CHAT_METRICS_FRAME); +} + /** * Split a raw socket buffer into complete `\x1e`-terminated frames, returning any * trailing partial frame as `rest` so it can be prepended to the next chunk. @@ -155,22 +177,37 @@ export function handshakeError(frame: Record | null): string | export interface ChatInvocationOptions { text: string; - /** Per-connection trace id (hex), reused as clientCorrelationId/traceId. */ + /** Per-invocation trace id (GUID). */ traceId: string; - /** Per-session id (GUID). */ + /** Client correlation id; defaults to {@link ChatInvocationOptions.traceId}. */ + clientCorrelationId?: string; + /** Per-session id (GUID, == the WS URL X-SessionId query). */ sessionId: string; + /** Per-request id (== the WS URL chatsessionid/clientrequestid query). */ + requestId: string; + /** + * Conversation id — MUST match the ConversationId query of the WS URL the + * invocation rides on (#10718: the server cross-checks the two). + */ + conversationId: string; + /** BCP-47 locale echoed in message.locale; defaults to "en-us". */ + locale?: string; + /** IANA time zone for message.locationInfo; defaults to "UTC". */ + timeZone?: string; + /** Hour offset for message.locationInfo; defaults to 0. */ + timeZoneOffset?: number; /** Whether this is the first turn of the conversation. */ isStartOfSession?: boolean; - /** Tier-specific option flags; left empty by default (tuned during live validation). */ + /** Tier-specific option flags; defaults to {@link M365_DEFAULT_OPTION_SETS}. */ optionsSets?: string[]; tone?: string; /** Tier-specific allowed message types; defaults to {@link ALLOWED_MESSAGE_TYPES}. */ allowedMessageTypes?: readonly string[]; /** - * Tier-specific disconnect behavior sent in every type:4 chat invocation. The work - * Surface rejects any value other than exactly "continue" (#8971). Defaults to "" - * for individual/consumer/EDU tiers; {@link resolveChatInvocationOverrides} returns - * "continue" for the enterprise tier. + * Tier-specific disconnect behavior sent in the type:4 chat invocation. The work + * surface rejects any value other than exactly "continue" (#8971), so the + * enterprise tier sends it; the 2026-08 recapture shows the individual/EDU + * surface omits the key entirely, so it is left out unless set (#10718). */ disconnectBehavior?: string; } @@ -185,7 +222,7 @@ export function resolveChatInvocationOverrides(tier: string | undefined): { optionsSets: string[]; tone: string; allowedMessageTypes: readonly string[]; - disconnectBehavior: string; + disconnectBehavior: string | undefined; } { if (tier === "enterprise") { return { @@ -197,9 +234,12 @@ export function resolveChatInvocationOverrides(tier: string | undefined): { } return { optionsSets: [...M365_DEFAULT_OPTION_SETS], - tone: "", + // #10718 — the 2026-08 recapture sends tone:"magic" (lowercase) on the + // individual/EDU surface; the old "" default is part of the dropped shape. + tone: "magic", allowedMessageTypes: ALLOWED_MESSAGE_TYPES, - disconnectBehavior: "", + // Omitted entirely on the individual/EDU wire (see ChatInvocationOptions). + disconnectBehavior: undefined, }; } @@ -207,7 +247,7 @@ export function resolveChatInvocationOverrides(tier: string | undefined): { * BizChat exposes several models selected by the `tone` field of the `type:4` chat * invocation (#7872, values confirmed against a real enterprise tenant in #7850). Each * tone-selected variant is registered as its own model id; the bare `copilot-m365` id is - * intentionally absent here so it keeps the tier default tone (`Magic` on enterprise, `""` + * intentionally absent here so it keeps the tier default tone (`Magic` on enterprise, `magic` * otherwise) resolved by {@link resolveChatInvocationOverrides}. */ export const M365_MODEL_TONE_MAP: Readonly> = { @@ -228,7 +268,14 @@ export function resolveToneForModel(model: string | undefined): string | undefin /** * Build the `type:4` chat invocation frame body (not yet `\x1e`-terminated). - * Mirrors the argument shape captured on the individual M365 path in #4042. + * Mirrors the argument shape recaptured from a working `m365.cloud.microsoft/chat` + * client in 2026-08 (#10718). Notable differences from the pre-#10718 shape: a + * populated `clientInfo` + `productThreadType:"Office"`, a `conversationId` + * matching the WS URL query, a rich `message` object, and no + * `spokenTextMode` / `extraExtensionParameters` / `isSbsSupported` / + * `renderReferencesBehindEOS` / `disconnectBehavior` — none of those are still + * observed on the wire, and the stale shape gets closed immediately after the + * invocation. */ export function buildChatInvocation(opts: ChatInvocationOptions): Record { return { @@ -237,33 +284,48 @@ export function buildChatInvocation(opts: ChatInvocationOptions): Record { - ws?.send(keepaliveFrame()); const overrides = resolveChatInvocationOverrides(input.tier); // Model-driven tone (#7872) wins over the tier default; a bare/unknown id // keeps the tier tone resolved above. const tone = resolveToneForModel(input.model) ?? overrides.tone; - ws?.send( - encodeFrame( - buildChatInvocation({ - text: input.prompt, - traceId, - sessionId, - isStartOfSession: true, - ...overrides, - tone, - }) - ) + const invocationFrame = encodeFrame( + buildChatInvocation({ + text: input.prompt, + traceId, + sessionId, + requestId, + conversationId, + isStartOfSession: true, + ...overrides, + tone, + }) ); + // #10718 — the invocation and its type:1 Metrics follow-up must land + // in ONE socket write, exactly as the browser sends them; a bare + // invocation (or one preceded by a type:6 ping) is silently dropped. + ws?.send(invocationFrame + metricsFrame()); }; ws.on("open", () => { @@ -273,6 +290,61 @@ export class CopilotM365WebExecutor extends BaseExecutor { ); } + /** + * #10718 — proactively refresh the M365 access token before opening the WS. + * A WS-handshake 401 surfaces as an error event INSIDE the SSE stream (the HTTP + * response is already 200 by then), so chatCore's generic 401→refresh→retry + * orchestration never triggers — the refresh has to happen here, pre-flight. + * No-ops for legacy connections without a stored refresh_token. + */ + private async ensureFreshCredentials( + credentials: ExecuteInput["credentials"], + onCredentialsRefreshed: ExecuteInput["onCredentialsRefreshed"], + log: ExecutorLog | null + ): Promise { + const psd = (credentials?.providerSpecificData ?? {}) as JsonRecord; + const refreshToken = + credentials.refreshToken || (typeof psd.refreshToken === "string" ? psd.refreshToken : ""); + if (!refreshToken) return; + + const current = currentM365AccessToken(credentials); + if (current && !tokenNeedsRefresh(current)) return; + + const tid = + decodeJwtClaims(current)?.tid || (typeof psd.tid === "string" ? psd.tid : "") || ""; + const result = await refreshM365AccessToken(refreshToken, tid, log ?? undefined); + if ("error" in result) { + // Fall through with the existing token — the WS layer will surface the failure. + return; + } + + const rotated = result.refreshToken || refreshToken; + const chathubPath = currentM365ChathubPath(credentials); + const next = { + ...credentials, + accessToken: result.accessToken, + refreshToken: rotated, + // Keep the pasted-format apiKey self-consistent so every resolution path + // (fresh column, stale column, dashboard re-read) sees the same token. + ...(chathubPath + ? { apiKey: `access_token=${result.accessToken}; chathubPath=${chathubPath}` } + : {}), + ...(result.expiresIn + ? { expiresAt: new Date(Date.now() + result.expiresIn * 1000).toISOString() } + : {}), + }; + Object.assign(credentials, next); + try { + await onCredentialsRefreshed?.(next); + } catch (err) { + // #7676 pattern: a persistence failure must never fail the user-facing response. + log?.warn?.( + "M365_TOKEN", + `persisting refreshed token failed (${err instanceof Error ? err.message : String(err)}) — will re-refresh next request` + ); + } + } + async execute(input: ExecuteInput): Promise<{ response: Response; url: string; @@ -293,6 +365,12 @@ export class CopilotM365WebExecutor extends BaseExecutor { }; } + await this.ensureFreshCredentials( + input.credentials, + input.onCredentialsRefreshed, + input.log ?? null + ); + const connectionParams = resolveConnectionParams(input.credentials); if ("error" in connectionParams) { return { diff --git a/open-sse/executors/cursor.ts b/open-sse/executors/cursor.ts index 89f7799b03..bc9ade9d27 100644 --- a/open-sse/executors/cursor.ts +++ b/open-sse/executors/cursor.ts @@ -57,6 +57,13 @@ import { type StreamingState as ComposerStreamingState, } from "../utils/composerToolCalls.ts"; import { cursorSessionManager, type CursorSession } from "../services/cursorSessionManager.ts"; +import { + CursorApiKeyExchangeError, + invalidateCursorSessionToken, + isCursorApiKey, + resolveCursorBearerToken, + stripCursorOAuthTokenPrefix, +} from "../services/cursorApiKeyAuth.ts"; import crypto from "crypto"; import * as fs from "node:fs"; import * as zlib from "node:zlib"; @@ -706,18 +713,44 @@ export function processFrame( } export class CursorExecutor extends BaseExecutor { - constructor() { - super("cursor", PROVIDERS.cursor); + constructor(provider: "cursor" | "cursor-api" = "cursor") { + super(provider, PROVIDERS[provider]); } buildUrl() { return CURSOR_AGENT_URL; } + /** + * API-key connections carry a `crsr_…` key that api2.cursor.sh does not + * accept as a Bearer; swap it for the exchanged session token before the + * h2 stream is opened. OAuth/IDE-session connections pass through untouched. + */ + async resolveExecutionCredentials(credentials) { + if (!isCursorApiKey(credentials?.apiKey)) return credentials; + try { + const accessToken = await resolveCursorBearerToken(credentials); + return { ...credentials, accessToken }; + } catch (err) { + const status = + err instanceof CursorApiKeyExchangeError ? err.status : HTTP_STATUS.SERVER_ERROR; + const message = err instanceof Error ? err.message : String(err); + return new Response( + JSON.stringify({ + error: { + message: sanitizeErrorMessage(message), + type: status === HTTP_STATUS.UNAUTHORIZED ? "authentication_error" : "connection_error", + code: "", + }, + }), + { status, headers: { "Content-Type": "application/json" } } + ); + } + } + buildHeaders(credentials) { - const accessToken = credentials.accessToken; const ghostMode = credentials.providerSpecificData?.ghostMode !== false; - const cleanToken = accessToken.includes("::") ? accessToken.split("::")[1] : accessToken; + const cleanToken = stripCursorOAuthTokenPrefix(credentials.accessToken ?? ""); const requestId = crypto.randomUUID(); const traceParent = `00-${crypto.randomBytes(16).toString("hex")}-${crypto.randomBytes(8).toString("hex")}-01`; @@ -825,7 +858,7 @@ export class CursorExecutor extends BaseExecutor { */ private async loadLiveCatalogIds(): Promise | undefined> { try { - const catalog = await getActiveSyncedCatalog("cursor"); + const catalog = await getActiveSyncedCatalog(this.provider); if (!catalog.models.length) return undefined; return new Set(catalog.models.map((model) => model.id)); } catch { @@ -1179,7 +1212,11 @@ export class CursorExecutor extends BaseExecutor { async execute({ model, body, stream, credentials, signal, log, upstreamExtraHeaders }) { const url = this.buildUrl(); - const headers = this.buildHeaders(credentials); + const executionCredentials = await this.resolveExecutionCredentials(credentials); + if (executionCredentials instanceof Response) { + return { response: executionCredentials, url, headers: {}, transformedBody: body }; + } + const headers = this.buildHeaders(executionCredentials); mergeUpstreamExtraHeaders(headers, upstreamExtraHeaders); const messages: ChatMessage[] = body.messages || []; @@ -1252,8 +1289,10 @@ export class CursorExecutor extends BaseExecutor { if (isToolFollowUp) { session = cursorSessionManager.acquire(conversationId); // #9029: content-based session match when client lacks conversation_id. - if (!session && !body.conversation_id) session = cursorSessionManager.findByToolCallIds( - messages.filter(m => m.role === "tool" && m.tool_call_id).map(m => m.tool_call_id!)); + if (!session && !body.conversation_id) + session = cursorSessionManager.findByToolCallIds( + messages.filter((m) => m.role === "tool" && m.tool_call_id).map((m) => m.tool_call_id!) + ); } if (session) { @@ -1334,6 +1373,9 @@ export class CursorExecutor extends BaseExecutor { if (opened.status !== 200) { const errBuf = await opened.consumeError(); const errText = errBuf.toString("utf8") || "Unknown error"; + if (opened.status === HTTP_STATUS.UNAUTHORIZED && isCursorApiKey(credentials.apiKey)) { + invalidateCursorSessionToken(credentials.apiKey); + } return { response: buildErrorResponse(opened.status, `[${opened.status}]: ${errText}`), url, diff --git a/open-sse/executors/index.ts b/open-sse/executors/index.ts index 3fc2bdf9b3..d82452bb7e 100644 --- a/open-sse/executors/index.ts +++ b/open-sse/executors/index.ts @@ -1,9 +1,5 @@ import { SEARCH_PROVIDERS } from "../config/searchRegistry.ts"; -import { - registerExecutor, - getRegisteredExecutor, - hasRegisteredExecutor, -} from "./registry.ts"; +import { registerExecutor, getRegisteredExecutor, hasRegisteredExecutor } from "./registry.ts"; import { AntigravityExecutor } from "./antigravity.ts"; import { GithubExecutor } from "./github.ts"; import { GheCopilotExecutor } from "./ghe-copilot.ts"; @@ -107,6 +103,8 @@ const executors = { "glm-cn": new GlmExecutor("glm-cn"), glmt: new GlmExecutor("glmt"), cu: new CursorExecutor(), // Alias for cursor + "cursor-api": new CursorExecutor("cursor-api"), + cua: new CursorExecutor("cursor-api"), "azure-openai": new AzureOpenAIExecutor(), "azure-ai": new AzureAiExecutor(), "command-code": new CommandCodeExecutor(), diff --git a/open-sse/handlers/chatCore.ts b/open-sse/handlers/chatCore.ts index d54689472c..e8d0c7835b 100644 --- a/open-sse/handlers/chatCore.ts +++ b/open-sse/handlers/chatCore.ts @@ -41,7 +41,11 @@ import { isStripReasoningRequested, } from "./chatCore/headers.ts"; import { markCodexScopeRateLimited } from "./chatCore/codexFailover.ts"; -import { isCodexOriginatedHeaders } from "../config/codexIdentity.ts"; +import { getCodexClientSessionId, isCodexOriginatedHeaders } from "../config/codexIdentity.ts"; +import { + noteCodexTurnStateProvenance, + readCodexTurnStateHeader, +} from "../config/codexTurnState.ts"; import { trackDevice, extractIpFromHeaders } from "../services/deviceTracker.ts"; import { getCombosCached } from "./chatCore/comboContextCache.ts"; export { clearCombosCache, clearUpstreamProxyConfigCache } from "./chatCore/comboContextCache.ts"; @@ -722,12 +726,13 @@ export async function handleChatCore({ copilotCompatibleReasoning, clientResponseFormat, } = resolveChatCoreRequestFormat({ clientRawRequest, body, provider, userAgent }); - const nativeOpenAICompatibleResponsesPassthrough = shouldUseNativeOpenAICompatibleResponsesPassthrough({ - provider, - sourceFormat, - endpointPath, - providerSpecificData: credentials?.providerSpecificData, - }); + const nativeOpenAICompatibleResponsesPassthrough = + shouldUseNativeOpenAICompatibleResponsesPassthrough({ + provider, + sourceFormat, + endpointPath, + providerSpecificData: credentials?.providerSpecificData, + }); const responsesInputItems = Array.isArray(body?.input) ? body.input : []; const customToolNames = collectCustomToolNamesForSourceFormat( sourceFormat, @@ -3387,6 +3392,15 @@ export async function handleChatCore({ const responseHeaders = new Headers(headersObj); stripStaleForwardingHeaders(responseHeaders); stripNextMiddlewareControlHeaders(responseHeaders); + // The upstream headers (turn-state included) are about to be committed + // to the client — record which connection minted the blob so a later + // cross-account echo can be stripped (Codex failover guard). + if (provider === "codex" && readCodexTurnStateHeader(responseHeaders)) { + noteCodexTurnStateProvenance( + getCodexClientSessionId(clientRawRequest?.headers), + rawResult._executionCredentials?.connectionId ?? credentials?.connectionId + ); + } const contentType = (responseHeaders.get("content-type") || "").toLowerCase(); const payload = await readNonStreamingResponseBody( rawResult.response, @@ -5106,6 +5120,17 @@ export async function handleChatCore({ comboStrategy, }); + // The streaming headers (turn-state included, when present) are committed to + // the client from here on — record which connection minted the blob so a + // later cross-account echo can be stripped (Codex failover guard). The + // in-place failover update means `credentials` is the winning account. + if (provider === "codex" && readCodexTurnStateHeader(providerResponse.headers)) { + noteCodexTurnStateProvenance( + getCodexClientSessionId(clientRawRequest?.headers), + credentials?.connectionId + ); + } + // Create transform stream with logger for streaming response let transformStream; const responseToolNameMap = mergeResponseToolNameMap( diff --git a/open-sse/handlers/chatCore/responseHeaders.ts b/open-sse/handlers/chatCore/responseHeaders.ts index 59c45ba829..8206304544 100644 --- a/open-sse/handlers/chatCore/responseHeaders.ts +++ b/open-sse/handlers/chatCore/responseHeaders.ts @@ -28,11 +28,18 @@ const STREAMING_RESPONSE_HEADER_DENYLIST = new Set([ "x-amz-security-token", "x-auth-token", "x-accel-buffering", - // 314-byte Codex session blob. It is not a client rate-limit signal and - // alone ate ~40% of the old 768-byte budget, evicting x-codex-*-used-percent. - "x-codex-turn-state", ]); +/** + * `x-codex-turn-state` is forwarded verbatim and EXEMPT from the forwarding + * budget. The real Codex client captures this ~314-byte blob from /responses + * (and echoes it back within the same turn), so dropping it breaks the + * protocol chain — but naively counting it against the budget used to evict + * the x-codex-*-used-percent quota headers (the reason it was denylisted + * under #10315-era budgeting). Carving it out keeps both. + */ +const CODEX_TURN_STATE_RESPONSE_HEADER = "x-codex-turn-state"; + const DEFAULT_FORWARDED_HEADER_BUDGET_BYTES = 768; /** @@ -206,7 +213,9 @@ export function buildStreamingResponseHeaders( STREAMING_RESPONSE_HEADER_DENYLIST.has(normalized) || connectionScopedHeaders.has(normalized) || isNextMiddlewareControlHeader(normalized) || - isOmniRouteInternalHeader(normalized) + isOmniRouteInternalHeader(normalized) || + // Forwarded separately below, outside the byte budget. + normalized === CODEX_TURN_STATE_RESPONSE_HEADER ) { return; } @@ -269,6 +278,10 @@ export function buildStreamingResponseHeaders( "X-Accel-Buffering": "no", [OMNIROUTE_RESPONSE_HEADERS.cache]: "MISS", }; + const codexTurnState = providerHeaders.get(CODEX_TURN_STATE_RESPONSE_HEADER)?.trim(); + if (codexTurnState) { + responseHeaders[CODEX_TURN_STATE_RESPONSE_HEADER] = codexTurnState; + } attachOmniRouteMetaHeaders(responseHeaders, meta); return responseHeaders; } diff --git a/open-sse/handlers/cursorCliProxy.ts b/open-sse/handlers/cursorCliProxy.ts new file mode 100644 index 0000000000..dbf742f8f6 --- /dev/null +++ b/open-sse/handlers/cursorCliProxy.ts @@ -0,0 +1,524 @@ +/** + * Cursor CLI passthrough. + * + * cursor-agent honours `--endpoint` / CURSOR_API_ENDPOINT and, with + * `network.useHttp1ForAgent: true`, talks to that endpoint exclusively over + * HTTP/1.1: unary Connect-RPC POSTs (`/aiserver.v1.*`, `/agent.v1.*`, + * `/aiserver.v1.BidiService/BidiAppend`), the agent turn as + * `/agent.v1.AgentService/RunSSE` (text/event-stream), OTLP traces on + * `/v1/traces`, and the API-key bootstrap `POST /auth/exchange_user_api_key`. + * + * Pointing the CLI at OmniRoute therefore only needs a thin forwarder: + * 1. `/auth/exchange_user_api_key` authenticates the CLI with an OmniRoute + * API key and hands back an OmniRoute-minted session JWT. The CLI reads + * `exp` from whatever JWT it receives and re-exchanges when the token is + * opaque or expired, so the minted token must be a real JWT with `exp`. + * 2. Every other path verifies that JWT, resolves an active `cursor-api` + * connection (the crsr_ key is exchanged for a session token), swaps the + * Authorization header and streams the upstream reply back unchanged. + * Each hop is recorded in call_logs. + */ + +import { SignJWT, jwtVerify, type JWTPayload } from "jose"; +import { z } from "zod"; +import { getApiKeyById, getApiKeyMetadata, validateApiKey } from "@/lib/db/apiKeys"; +import { getProviderConnections } from "@/lib/db/providers"; +import { saveCallLog } from "@/lib/usage/callLogs"; +import { isRequireApiKeyEnabled } from "@/shared/utils/featureFlags"; +import { HTTP_STATUS } from "../config/constants.ts"; +import { + CURSOR_API_BASE_URL, + CURSOR_API_KEY_EXCHANGE_PATH, + CursorApiKeyExchangeError, + invalidateCursorSessionToken, + isCursorApiKey, + resolveCursorBearerToken, +} from "../services/cursorApiKeyAuth.ts"; +import { sanitizeErrorMessage } from "../utils/error.ts"; + +export const CURSOR_CLI_PROXY_PREFIX = "/api/cursor-cli"; +export const CURSOR_CLI_SESSION_ISSUER = "omniroute"; +export const CURSOR_CLI_SESSION_AUDIENCE = "cursor-cli"; +export const CURSOR_CLI_SESSION_TTL_SECONDS = 60 * 60; +export const CURSOR_CLI_REQUEST_TYPE = "cursor-cli"; +const ANONYMOUS_SUBJECT = "anonymous"; +const PROVIDER_ID = "cursor-api"; + +const REQUEST_HEADER_DENYLIST = new Set([ + "authorization", + "host", + "connection", + "content-length", + "accept-encoding", + "keep-alive", + "proxy-authorization", + "proxy-connection", + "te", + "trailer", + "transfer-encoding", + "upgrade", + "x-forwarded-for", + "x-forwarded-host", + "x-forwarded-proto", + "x-real-ip", + "cookie", +]); + +const RESPONSE_HEADER_DENYLIST = new Set([ + "connection", + "content-encoding", + "content-length", + "keep-alive", + "transfer-encoding", + "set-cookie", +]); + +const exchangeBodySchema = z.object({}).passthrough(); + +const sessionClaimsSchema = z.object({ + sub: z.string().min(1), + iss: z.literal(CURSOR_CLI_SESSION_ISSUER), + aud: z.union([ + z.literal(CURSOR_CLI_SESSION_AUDIENCE), + z.array(z.string()).refine((list) => list.includes(CURSOR_CLI_SESSION_AUDIENCE)), + ]), + exp: z.number(), + name: z.string().nullable().optional(), +}); + +export type CursorCliPrincipal = { + apiKeyId: string | null; + apiKeyName: string | null; +}; + +export type CursorCliConnectionLike = { + id?: unknown; + apiKey?: unknown; + accessToken?: unknown; + priority?: unknown; + rateLimitedUntil?: unknown; +}; + +export type CursorCliProxyDeps = { + fetchImpl: typeof fetch; + now: () => number; + getSecret: () => string | undefined; + validateApiKey: (key: string) => Promise; + getApiKeyMetadata: (key: string) => Promise<{ id: string; name: string } | null>; + getApiKeyById: (id: string) => Promise<{ isActive?: unknown; revokedAt?: unknown } | null>; + requireApiKey: () => boolean; + listCursorConnections: () => Promise; + resolveBearer: (credentials: { + apiKey?: string | null; + accessToken?: string | null; + }) => Promise; + invalidateBearer: (apiKey: string) => void; + saveCallLog: (entry: Record) => Promise; + upstreamBaseUrl: string; +}; + +const defaultDeps: CursorCliProxyDeps = { + fetchImpl: (input, init) => fetch(input, init), + now: () => Date.now(), + getSecret: () => process.env.JWT_SECRET, + validateApiKey: (key) => validateApiKey(key), + getApiKeyMetadata: async (key) => { + const meta = await getApiKeyMetadata(key); + return meta ? { id: meta.id, name: meta.name } : null; + }, + getApiKeyById: (id) => getApiKeyById(id), + requireApiKey: () => isRequireApiKeyEnabled(), + listCursorConnections: async () => + (await getProviderConnections({ + provider: PROVIDER_ID, + isActive: true, + })) as CursorCliConnectionLike[], + resolveBearer: (credentials) => resolveCursorBearerToken(credentials), + invalidateBearer: (apiKey) => invalidateCursorSessionToken(apiKey), + saveCallLog: (entry) => saveCallLog(entry), + upstreamBaseUrl: CURSOR_API_BASE_URL, +}; + +function jsonResponse(status: number, body: Record): Response { + return new Response(JSON.stringify(body), { + status, + headers: { "content-type": "application/json" }, + }); +} + +function connectError(status: number, code: string, message: string): Response { + return jsonResponse(status, { code, message: sanitizeErrorMessage(message) }); +} + +function extractBearer(request: Request): string | null { + const header = request.headers.get("authorization") ?? ""; + const match = /^Bearer\s+(.+)$/i.exec(header.trim()); + return match ? match[1].trim() : null; +} + +function secretKey(secret: string): Uint8Array { + return new TextEncoder().encode(secret); +} + +export function normalizeCursorCliPath(segments: readonly string[]): string { + return "/" + segments.map((segment) => encodeURIComponent(decodeURIComponent(segment))).join("/"); +} + +async function authenticateExchange( + request: Request, + deps: CursorCliProxyDeps +): Promise { + const bearer = extractBearer(request); + if (bearer && (await deps.validateApiKey(bearer))) { + const meta = await deps.getApiKeyMetadata(bearer); + return { apiKeyId: meta?.id ?? null, apiKeyName: meta?.name ?? null }; + } + if (!deps.requireApiKey()) { + return { apiKeyId: null, apiKeyName: null }; + } + return connectError( + HTTP_STATUS.UNAUTHORIZED, + "unauthenticated", + "CURSOR_API_KEY must be an OmniRoute API key when OmniRoute requires API keys" + ); +} + +export async function mintCursorCliSessionToken( + principal: CursorCliPrincipal, + secret: string, + nowMs: number +): Promise { + const nowSeconds = Math.floor(nowMs / 1000); + return new SignJWT({ name: principal.apiKeyName }) + .setProtectedHeader({ alg: "HS256", typ: "JWT" }) + .setIssuer(CURSOR_CLI_SESSION_ISSUER) + .setAudience(CURSOR_CLI_SESSION_AUDIENCE) + .setSubject(principal.apiKeyId ?? ANONYMOUS_SUBJECT) + .setIssuedAt(nowSeconds) + .setExpirationTime(nowSeconds + CURSOR_CLI_SESSION_TTL_SECONDS) + .sign(secretKey(secret)); +} + +async function verifyCursorCliSessionToken( + token: string, + secret: string, + nowMs: number +): Promise { + let payload: JWTPayload; + try { + ({ payload } = await jwtVerify(token, secretKey(secret), { + issuer: CURSOR_CLI_SESSION_ISSUER, + audience: CURSOR_CLI_SESSION_AUDIENCE, + currentDate: new Date(nowMs), + })); + } catch { + return null; + } + const claims = sessionClaimsSchema.safeParse(payload); + if (!claims.success) return null; + return { + apiKeyId: claims.data.sub === ANONYMOUS_SUBJECT ? null : claims.data.sub, + apiKeyName: claims.data.name ?? null, + }; +} + +async function isPrincipalStillValid( + principal: CursorCliPrincipal, + deps: CursorCliProxyDeps +): Promise { + if (!principal.apiKeyId) return !deps.requireApiKey(); + const row = await deps.getApiKeyById(principal.apiKeyId); + if (!row) return false; + if (row.isActive === false) return false; + return !(typeof row.revokedAt === "string" && row.revokedAt.trim() !== ""); +} + +type ResolvedConnection = { + connectionId: string | null; + bearer: string; + apiKey: string | null; +}; + +function connectionPriority(connection: CursorCliConnectionLike): number { + return typeof connection.priority === "number" ? connection.priority : Number.MAX_SAFE_INTEGER; +} + +function isCoolingDown(connection: CursorCliConnectionLike, nowMs: number): boolean { + if (typeof connection.rateLimitedUntil !== "string") return false; + const until = Date.parse(connection.rateLimitedUntil); + return Number.isFinite(until) && until > nowMs; +} + +async function resolveUpstreamConnection( + deps: CursorCliProxyDeps +): Promise { + const connections = (await deps.listCursorConnections()) + .filter((connection) => !isCoolingDown(connection, deps.now())) + .sort((a, b) => connectionPriority(a) - connectionPriority(b)); + if (connections.length === 0) { + return connectError( + HTTP_STATUS.SERVICE_UNAVAILABLE, + "unavailable", + "No active Cursor API connection configured in OmniRoute" + ); + } + let lastError: unknown = null; + for (const connection of connections) { + const apiKey = isCursorApiKey(connection.apiKey) ? connection.apiKey : null; + const accessToken = typeof connection.accessToken === "string" ? connection.accessToken : null; + try { + const bearer = await deps.resolveBearer({ apiKey, accessToken }); + return { + connectionId: typeof connection.id === "string" ? connection.id : null, + bearer, + apiKey, + }; + } catch (err) { + lastError = err; + } + } + const status = + lastError instanceof CursorApiKeyExchangeError ? lastError.status : HTTP_STATUS.BAD_GATEWAY; + const message = lastError instanceof Error ? lastError.message : "Cursor credential unavailable"; + return connectError( + status, + status === HTTP_STATUS.UNAUTHORIZED ? "unauthenticated" : "unavailable", + message + ); +} + +function buildUpstreamHeaders(request: Request, bearer: string): Headers { + const headers = new Headers(); + request.headers.forEach((value, name) => { + if (!REQUEST_HEADER_DENYLIST.has(name.toLowerCase())) headers.set(name, value); + }); + headers.set("authorization", `Bearer ${bearer}`); + return headers; +} + +function buildDownstreamHeaders(upstream: Response): Headers { + const headers = new Headers(); + upstream.headers.forEach((value, name) => { + if (!RESPONSE_HEADER_DENYLIST.has(name.toLowerCase())) headers.set(name, value); + }); + return headers; +} + +type CallLogInput = { + method: string; + path: string; + status: number; + startedAt: number; + principal: CursorCliPrincipal | null; + connectionId: string | null; + error?: string | null; +}; + +function recordCall(deps: CursorCliProxyDeps, input: CallLogInput): void { + void deps + .saveCallLog({ + method: input.method, + path: `${CURSOR_CLI_PROXY_PREFIX}${input.path}`, + status: input.status, + model: "-", + provider: PROVIDER_ID, + connectionId: input.connectionId, + duration: Math.max(0, deps.now() - input.startedAt), + apiKeyId: input.principal?.apiKeyId ?? null, + apiKeyName: input.principal?.apiKeyName ?? null, + requestType: CURSOR_CLI_REQUEST_TYPE, + sourceFormat: CURSOR_CLI_REQUEST_TYPE, + targetFormat: CURSOR_CLI_REQUEST_TYPE, + error: input.error ? { message: sanitizeErrorMessage(input.error) } : null, + }) + .catch(() => undefined); +} + +function streamWithCompletionLog( + body: ReadableStream, + onDone: (error?: string) => void +): ReadableStream { + const reader = body.getReader(); + let settled = false; + const settle = (error?: string) => { + if (settled) return; + settled = true; + onDone(error); + }; + return new ReadableStream({ + async pull(controller) { + try { + const { done, value } = await reader.read(); + if (done) { + settle(); + controller.close(); + return; + } + controller.enqueue(value); + } catch (err) { + settle(err instanceof Error ? err.message : "upstream stream failed"); + controller.error(err); + } + }, + cancel(reason) { + settle(reason instanceof Error ? reason.message : "stream cancelled"); + return reader.cancel(reason); + }, + }); +} + +async function handleExchange( + request: Request, + startedAt: number, + deps: CursorCliProxyDeps +): Promise { + if (request.method !== "POST") { + return connectError(405, "unimplemented", "Use POST"); + } + const rawBody = await request.text(); + if (rawBody.trim().length > 0) { + let parsed: unknown; + try { + parsed = JSON.parse(rawBody); + } catch { + return connectError(HTTP_STATUS.BAD_REQUEST, "invalid_argument", "Body must be JSON"); + } + if (!exchangeBodySchema.safeParse(parsed).success) { + return connectError( + HTTP_STATUS.BAD_REQUEST, + "invalid_argument", + "Body must be a JSON object" + ); + } + } + + const principal = await authenticateExchange(request, deps); + if (principal instanceof Response) { + recordCall(deps, { + method: request.method, + path: CURSOR_API_KEY_EXCHANGE_PATH, + status: principal.status, + startedAt, + principal: null, + connectionId: null, + error: "OmniRoute API key rejected", + }); + return principal; + } + + const secret = deps.getSecret(); + if (!secret || secret.trim().length === 0) { + return connectError( + HTTP_STATUS.SERVICE_UNAVAILABLE, + "unavailable", + "JWT_SECRET is not configured; the Cursor CLI passthrough cannot mint session tokens" + ); + } + + const token = await mintCursorCliSessionToken(principal, secret, deps.now()); + recordCall(deps, { + method: request.method, + path: CURSOR_API_KEY_EXCHANGE_PATH, + status: 200, + startedAt, + principal, + connectionId: null, + }); + return jsonResponse(200, { accessToken: token, refreshToken: token }); +} + +async function handleForward( + request: Request, + path: string, + startedAt: number, + deps: CursorCliProxyDeps +): Promise { + const secret = deps.getSecret(); + const bearer = extractBearer(request); + const principal = + bearer && secret ? await verifyCursorCliSessionToken(bearer, secret, deps.now()) : null; + if (!principal || !(await isPrincipalStillValid(principal, deps))) { + return connectError( + HTTP_STATUS.UNAUTHORIZED, + "unauthenticated", + "Missing or expired OmniRoute Cursor CLI session token" + ); + } + + const resolved = await resolveUpstreamConnection(deps); + if (resolved instanceof Response) { + recordCall(deps, { + method: request.method, + path, + status: resolved.status, + startedAt, + principal, + connectionId: null, + error: "No usable Cursor connection", + }); + return resolved; + } + + const search = new URL(request.url).search; + const upstreamUrl = `${deps.upstreamBaseUrl}${path}${search}`; + const hasBody = request.method !== "GET" && request.method !== "HEAD"; + let upstream: Response; + try { + upstream = await deps.fetchImpl(upstreamUrl, { + method: request.method, + headers: buildUpstreamHeaders(request, resolved.bearer), + body: hasBody ? request.body : undefined, + signal: request.signal, + redirect: "manual", + ...(hasBody ? { duplex: "half" } : {}), + } as RequestInit); + } catch (err) { + const message = err instanceof Error ? err.message : "upstream request failed"; + recordCall(deps, { + method: request.method, + path, + status: HTTP_STATUS.BAD_GATEWAY, + startedAt, + principal, + connectionId: resolved.connectionId, + error: message, + }); + return connectError(HTTP_STATUS.BAD_GATEWAY, "unavailable", message); + } + + if (upstream.status === HTTP_STATUS.UNAUTHORIZED && resolved.apiKey) { + deps.invalidateBearer(resolved.apiKey); + } + + const logInput: CallLogInput = { + method: request.method, + path, + status: upstream.status, + startedAt, + principal, + connectionId: resolved.connectionId, + }; + const headers = buildDownstreamHeaders(upstream); + if (!upstream.body) { + recordCall(deps, logInput); + return new Response(null, { status: upstream.status, headers }); + } + const body = streamWithCompletionLog(upstream.body, (error) => + recordCall(deps, { ...logInput, error: error ?? null }) + ); + return new Response(body, { status: upstream.status, headers }); +} + +export async function handleCursorCliProxy( + request: Request, + segments: readonly string[], + overrides: Partial = {} +): Promise { + const deps: CursorCliProxyDeps = { ...defaultDeps, ...overrides }; + const startedAt = deps.now(); + const path = normalizeCursorCliPath(segments); + if (path === CURSOR_API_KEY_EXCHANGE_PATH) { + return handleExchange(request, startedAt, deps); + } + return handleForward(request, path, startedAt, deps); +} diff --git a/open-sse/mcp-server/httpTransport.ts b/open-sse/mcp-server/httpTransport.ts index ab742858c6..d8826c738c 100644 --- a/open-sse/mcp-server/httpTransport.ts +++ b/open-sse/mcp-server/httpTransport.ts @@ -284,12 +284,30 @@ export async function handleMcpStreamableHTTP(request: Request): Promise { + if (request.method === "POST") { + try { + const body = await request.clone().json(); + const isInitialize = Array.isArray(body) + ? body.some((req: RpcRequest) => req?.method === "initialize") + : (body as RpcRequest)?.method === "initialize"; + + if (isInitialize) { + console.log("[MCP] New client initialize detected, resetting SSE singleton..."); + closeSseTransport(); + } + } catch (err) {} + } const { transport } = ensureSseServer(); try { diff --git a/open-sse/services/codexQuotaFetcher.ts b/open-sse/services/codexQuotaFetcher.ts index eb588ac3ba..12f955906d 100644 --- a/open-sse/services/codexQuotaFetcher.ts +++ b/open-sse/services/codexQuotaFetcher.ts @@ -25,6 +25,7 @@ import { import { registerQuotaFetcher, registerQuotaWindows, type QuotaInfo } from "./quotaPreflight.ts"; import { registerMonitorFetcher } from "./quotaMonitor.ts"; import { throttleQuotaFetch } from "./quotaFetchThrottle.ts"; +import { getCodexBackendIdentityHeaders } from "../config/codexClient.ts"; /** * Stable identifiers for Codex's quota windows. These match the quota keys @@ -222,6 +223,9 @@ export async function fetchCodexQuota( Authorization: `Bearer ${meta.accessToken}`, "Content-Type": "application/json", Accept: "application/json", + // Canonical Codex backend identity (UA + originator + version), same + // chain as inference — see getCodexUsage. + ...getCodexBackendIdentityHeaders(), }; if (meta.workspaceId) { diff --git a/open-sse/services/combo.ts b/open-sse/services/combo.ts index c9ccae9a97..982775f69b 100644 --- a/open-sse/services/combo.ts +++ b/open-sse/services/combo.ts @@ -235,6 +235,14 @@ import { resolveComboTargets, } from "./combo/comboStructure.ts"; import { getKnownContextOverflow } from "./combo/knownContextOverflow.ts"; +import { + createInvocationId, + finalizeComboTrace, + finishComboTrace, + getComboTrace, + recordComboDecision, + startComboTrace, +} from "./combo/decisionTrace.ts"; import { QUOTA_SOFT_DEPRIORITIZE_FACTOR, setCandidateQuotaSoftPenalty, @@ -607,7 +615,25 @@ export { pinIsDurablyUnhealthy }; /** @param {string} errorText */ /** @param {object} options */ -export async function handleComboChat({ +/** + * #10681 egress: every combo response carries the opaque trace id in an + * `X-OmniRoute-Combo-Trace` header so a post-incident lookup of the ordered + * per-target decisions is possible; the finalized summary is also emitted as + * one metadata-only log line for durability across restarts. + */ +export async function handleComboChat(options: HandleComboChatOptions): Promise { + const traceInvocationId = options.invocationId ?? createInvocationId(); + const response = await handleComboChatInner({ ...options, invocationId: traceInvocationId }); + response.headers.set("X-OmniRoute-Combo-Trace", traceInvocationId); + const trace = getComboTrace(traceInvocationId); + options.log.info( + "COMBO", + `combo trace ${traceInvocationId} terminal=${JSON.stringify(trace?.terminal ?? null)} decisions=${trace?.decisions.length ?? 0}` + ); + return response; +} + +async function handleComboChatInner({ body, combo, handleSingleModel, @@ -627,6 +653,7 @@ export async function handleComboChat({ sourceFormat = null, endpointPath = null, requestHeaders = null, + invocationId, }: HandleComboChatOptions): Promise { const comboCtx = createComboContext({ body, combo, settings, relayOptions, log }); const { @@ -643,6 +670,10 @@ export async function handleComboChat({ } = phaseComboSetup(comboCtx); body = comboCtx.body; + // #10681: opaque per-invocation decision trace (safe routing metadata only). + const traceInvocationId = invocationId ?? createInvocationId(); + startComboTrace(traceInvocationId, { strategy, comboName: combo.name }); + const handleSingleModelWithTimeout = buildTargetTimeoutRunner({ handleSingleModel, comboTargetTimeoutMs, @@ -1019,6 +1050,9 @@ export async function handleComboChat({ }); const runningTasks = new Set>(); let anySuccess = false; + // #10681: steps already recorded as dispatched (so per-target retries do not + // duplicate the decision). + const dispatchedTargets = new Set(); const abortControllers = new Map(); const zeroLatencyOptimizationsEnabled = config.zeroLatencyOptimizationsEnabled === true; const hasProtectedPriorityTarget = @@ -1044,6 +1078,12 @@ export async function handleComboChat({ const cb = getCircuitBreaker(provider); if (cb.getStatus().state === "OPEN") { log.info("COMBO", `Skipping ${modelStr} — circuit breaker OPEN for ${provider}`); + recordComboDecision(traceInvocationId, { + step: target.executionKey, + target: modelStr, + decision: "skipped_before_dispatch", + reason: "circuit_open", + }); if (i > 0) fallbackCount++; return stopProtectedPriorityTarget(`Provider ${provider} circuit breaker is open`); } @@ -1054,6 +1094,12 @@ export async function handleComboChat({ isProviderInCooldown(provider, target.connectionId ?? undefined, resilienceSettings) ) { log.info("COMBO", `Skipping ${modelStr} — provider ${provider} in global cooldown`); + recordComboDecision(traceInvocationId, { + step: target.executionKey, + target: modelStr, + decision: "skipped_before_dispatch", + reason: "provider_cooldown", + }); if (i > 0) fallbackCount++; return stopProtectedPriorityTarget(`Provider ${provider} is in cooldown`); } @@ -1081,6 +1127,12 @@ export async function handleComboChat({ ); if (exhaustedSkip) { log.info("COMBO", exhaustedSkip); + recordComboDecision(traceInvocationId, { + step: target.executionKey, + target: modelStr, + decision: "skipped_before_dispatch", + reason: "request_exhaustion", + }); if (i > 0) fallbackCount++; return stopProtectedPriorityTarget(`Target ${modelStr} is unavailable`); } @@ -1088,6 +1140,12 @@ export async function handleComboChat({ // Pre-check: skip models locked by the resilience system (model-level lockout) if (provider && rawModel && isModelLocked(provider, target.connectionId || "", rawModel)) { log.info("COMBO", `Skipping ${modelStr} — model locked by resilience (cooldown active)`); + recordComboDecision(traceInvocationId, { + step: target.executionKey, + target: modelStr, + decision: "skipped_before_dispatch", + reason: "model_lockout", + }); if (i > 0) fallbackCount++; return stopProtectedPriorityTarget(`Model ${modelStr} is locked`); } @@ -1114,6 +1172,12 @@ export async function handleComboChat({ "COMBO", `Skipping ${modelStr} — quota exhaustion cutoff (${quotaCutoff.reason || "quota_exhausted"})` ); + recordComboDecision(traceInvocationId, { + step: target.executionKey, + target: modelStr, + decision: "skipped_before_dispatch", + reason: "quota_cutoff", + }); if (i > 0) fallbackCount++; observeFailure(true, target.executionKey); if (protectedPriorityTarget) { @@ -1162,6 +1226,12 @@ export async function handleComboChat({ "COMBO", `Skipping ${modelStr} — no credentials available or model excluded` ); + recordComboDecision(traceInvocationId, { + step: target.executionKey, + target: modelStr, + decision: "skipped_before_dispatch", + reason: "availability", + }); if (i > 0) fallbackCount++; return stopProtectedPriorityTarget(`Model ${modelStr} is unavailable`); } @@ -1173,6 +1243,12 @@ export async function handleComboChat({ const gateResult = checkCredentialGate(connectionId, provider, modelStr); if (gateResult.allowed === false) { logCredentialSkip(log, modelStr, gateResult.reason || "Credential gate blocked"); + recordComboDecision(traceInvocationId, { + step: target.executionKey, + target: modelStr, + decision: "skipped_before_dispatch", + reason: "credential_gate", + }); if (i > 0) fallbackCount++; return stopProtectedPriorityTarget(`Credential gate blocked ${modelStr}`); } @@ -1187,6 +1263,12 @@ export async function handleComboChat({ "COMBO", `Skipping ${modelStr} — connection ${connectionId} is at max concurrency cap (${maxConcurrentCap})` ); + recordComboDecision(traceInvocationId, { + step: target.executionKey, + target: modelStr, + decision: "skipped_before_dispatch", + reason: "concurrency_cap", + }); if (i > 0) fallbackCount++; return stopProtectedPriorityTarget(`Connection capacity reached for ${modelStr}`); } @@ -1202,6 +1284,12 @@ export async function handleComboChat({ !(await perTargetAdmission({ modelStr, executionKey: target.executionKey, body })) ) { log.info("COMBO", `Skipping ${modelStr} — admission lane full (#9654)`); + recordComboDecision(traceInvocationId, { + step: target.executionKey, + target: modelStr, + decision: "skipped_before_dispatch", + reason: "admission_lane", + }); if (i > 0) fallbackCount++; return null; } @@ -1257,6 +1345,12 @@ export async function handleComboChat({ "COMBO", `Predictive TTFT Circuit Breaker: skipping ${modelStr} (avg ${m.avgLatencyMs}ms > max ${config.predictiveTtftMs}ms)` ); + recordComboDecision(traceInvocationId, { + step: target.executionKey, + target: modelStr, + decision: "skipped_before_dispatch", + reason: "predictive_ttft", + }); return stopProtectedPriorityTarget(`Predictive latency check rejected ${modelStr}`); } } @@ -1386,6 +1480,15 @@ export async function handleComboChat({ : "", fingerprint: resolveTargetFingerprint(target) ?? "", }); + // #10681: record dispatch once per target (retries keep the first decision). + if (!dispatchedTargets.has(target.executionKey)) { + dispatchedTargets.add(target.executionKey); + recordComboDecision(traceInvocationId, { + step: target.executionKey, + target: modelStr, + decision: "dispatched", + }); + } const result = await handleSingleModelWithTimeout(attemptBody, modelStr, { ...targetForAttempt, effectiveComboStrategy: strategy, @@ -2297,10 +2400,16 @@ export async function handleComboChat({ await Promise.race([globalPromise, Promise.all([...runningTasks])]); } + // #10681: finalize the decision trace (success). + finalizeComboTrace(traceInvocationId, orderedTargets); + finishComboTrace(traceInvocationId, { status: 200 }); if (anySuccess) { return await globalPromise; } + // #10681: finalize the decision trace (global timeout). + finalizeComboTrace(traceInvocationId, orderedTargets); + finishComboTrace(traceInvocationId, { status: 504 }); // Global combo timeout: return aggregated error immediately, skipping set retries. if (comboExpired) { const summary = buildRedactedSummary(comboErrors); @@ -2343,6 +2452,9 @@ export async function handleComboChat({ if (setTry < maxSetRetries) continue; // All set retries exhausted — return the final error + // #10681: finalize the decision trace (all targets failed or skipped). + finalizeComboTrace(traceInvocationId, orderedTargets); + finishComboTrace(traceInvocationId, { status: 503 }); if (!lastStatus) { if (recordedAttempts === 0) { notifyWebhookEvent("request.failed", { @@ -2443,6 +2555,9 @@ export async function handleComboChat({ } } + // #10681: finalize the decision trace with the aggregated terminal status. + finalizeComboTrace(traceInvocationId, orderedTargets); + finishComboTrace(traceInvocationId, { status }); // Retry-after decoration is separate from the wait decision above: only // rate-limit-class final statuses may carry a `(reset after ...)` suffix // (see unavailableRetryGate.ts — do not stitch a peer target's window onto diff --git a/open-sse/services/combo/decisionTrace.ts b/open-sse/services/combo/decisionTrace.ts new file mode 100644 index 0000000000..7660af7ea0 --- /dev/null +++ b/open-sse/services/combo/decisionTrace.ts @@ -0,0 +1,175 @@ +/** + * #10681: opaque per-invocation combo decision trace. + * + * Priority combos can be impossible to audit after a mixed fallback: dispatched + * attempts are persisted in call_logs, but candidates excluded before dispatch + * (circuit open, provider cooldown, model lockout, quota cutoff, availability, + * credential gate, concurrency cap, admission lane, predictive TTFT) leave no + * correlated decision record. This module records one ordered, allowlisted + * decision per target per invocation so operators can reconstruct what the + * chain actually did. + * + * SAFETY CONTRACT: the trace contains ONLY routing metadata — invocation id, + * strategy, combo name, per-target provider/model, decision, allowlisted skip + * reason, timestamps, terminal status. Never prompts, request/response bodies, + * headers, credentials, account ids, or raw upstream error strings. + * + * Retention: bounded in-memory (TTL + LRU cap) — see TRACE_TTL_MS/MAX_TRACES. + */ +import { randomUUID } from "node:crypto"; + +export const COMBO_SKIP_REASONS = [ + "circuit_open", + "provider_cooldown", + "request_exhaustion", + "model_lockout", + "quota_cutoff", + "availability", + "credential_gate", + "concurrency_cap", + "admission_lane", + "predictive_ttft", +] as const; + +export type ComboSkipReason = (typeof COMBO_SKIP_REASONS)[number]; + +export type ComboDecision = "dispatched" | "skipped_before_dispatch" | "not_reached"; + +export interface ComboTraceEntry { + /** Safe internal identifier of the combo step (execution key). */ + step: string; + /** Safe routing metadata: "/". */ + target: string; + decision: ComboDecision; + reason?: ComboSkipReason; + ts: number; +} + +export interface ComboTrace { + invocationId: string; + createdAt: number; + strategy: string | null; + comboName: string | null; + decisions: ComboTraceEntry[]; + terminal: { status: number | null; errorClass: string | null } | null; +} + +const TRACE_TTL_MS = 30 * 60 * 1000; +const MAX_TRACES = 2000; +const traces = new Map(); + +export function createInvocationId(): string { + return `combo-${randomUUID()}`; +} + +function isComboSkipReason(value: unknown): value is ComboSkipReason { + return typeof value === "string" && (COMBO_SKIP_REASONS as readonly string[]).includes(value); +} + +/** Test hook: clear the in-memory store. */ +export function resetComboTraceStore(): void { + traces.clear(); +} + +export function startComboTrace( + invocationId: string, + meta: { strategy?: string | null; comboName?: string | null } +): void { + pruneExpired(); + if (traces.size >= MAX_TRACES) { + // Prefer evicting a FINALIZED trace so in-flight (unfinalized) invocations + // survive a burst; fall back to the oldest trace overall. + let victim: ComboTrace | null = null; + for (const trace of traces.values()) { + if (trace.terminal !== null && (!victim || trace.createdAt < victim.createdAt)) { + victim = trace; + } + } + if (!victim) { + for (const trace of traces.values()) { + if (!victim || trace.createdAt < victim.createdAt) victim = trace; + } + } + if (victim) traces.delete(victim.invocationId); + } + if (!traces.has(invocationId)) { + traces.set(invocationId, { + invocationId, + createdAt: Date.now(), + strategy: meta.strategy ?? null, + comboName: meta.comboName ?? null, + decisions: [], + terminal: null, + }); + } +} + +export function recordComboDecision( + invocationId: string, + entry: Omit & { reason?: unknown } +): void { + const trace = traces.get(invocationId); + if (!trace) return; + if (entry.reason !== undefined && !isComboSkipReason(entry.reason)) { + throw new Error( + `invalid combo skip reason: ${String(entry.reason)} (allowlist: ${COMBO_SKIP_REASONS.join(", ")})` + ); + } + trace.decisions.push({ + step: entry.step, + target: entry.target, + decision: entry.decision, + reason: entry.reason as ComboSkipReason | undefined, + ts: Date.now(), + }); +} + +export function finishComboTrace( + invocationId: string, + terminal: { status: number | null; errorClass?: string | null } +): void { + const trace = traces.get(invocationId); + if (!trace) return; + trace.terminal = { status: terminal.status, errorClass: terminal.errorClass ?? null }; +} + +/** + * Mark every target that received no decision as not_reached and return the + * trace. Safe to call on success and failure paths; idempotent. + */ +export function finalizeComboTrace( + invocationId: string, + orderedTargets: Array<{ executionKey: string; modelStr: string }> +): ComboTrace | null { + const trace = traces.get(invocationId); + if (!trace) return null; + const decided = new Set(trace.decisions.map((d) => d.step)); + for (const t of orderedTargets) { + if (!decided.has(t.executionKey)) { + trace.decisions.push({ + step: t.executionKey, + target: t.modelStr, + decision: "not_reached", + ts: Date.now(), + }); + } + } + return trace; +} + +export function getComboTrace(invocationId: string): ComboTrace | null { + const trace = traces.get(invocationId); + if (!trace) return null; + if (Date.now() - trace.createdAt > TRACE_TTL_MS) { + traces.delete(invocationId); + return null; + } + return trace; +} + +function pruneExpired(): void { + const now = Date.now(); + for (const [id, trace] of traces) { + if (now - trace.createdAt > TRACE_TTL_MS) traces.delete(id); + } +} diff --git a/open-sse/services/combo/dispatchPrelude.ts b/open-sse/services/combo/dispatchPrelude.ts index 2f5361a4cf..8fbaff5c82 100644 --- a/open-sse/services/combo/dispatchPrelude.ts +++ b/open-sse/services/combo/dispatchPrelude.ts @@ -65,6 +65,7 @@ type RunCombo = (options: HandleComboChatOptions) => Promise; * hand back to it when it dispatches a nested combo-ref. */ type PreludeBaseOptionArgs = { + invocationId?: string; body: Record; combo: ComboLike; handleSingleModel: HandleSingleModel; @@ -103,6 +104,7 @@ function buildBaseOptions(a: PreludeBaseOptionArgs): HandleComboChatOptions { signal: a.signal, apiKeyAllowedConnections: a.apiKeyAllowedConnections, hiddenModelsByProvider: a.hiddenModelsByProvider, + invocationId: a.invocationId, clientManagedResponsesContext: a.clientManagedResponsesContext, perTargetAdmission: a.perTargetAdmission, deferContextOverflowWhenCompressible: a.deferContextOverflowWhenCompressible, diff --git a/open-sse/services/combo/types.ts b/open-sse/services/combo/types.ts index 03349e43c7..83a7f26693 100644 --- a/open-sse/services/combo/types.ts +++ b/open-sse/services/combo/types.ts @@ -100,6 +100,8 @@ export type ComboNestingContext = { export type HiddenModelsByProvider = ReadonlyMap>; export type HandleComboChatOptions = { + /** #10681: optional opaque parent invocation id for the decision trace. */ + invocationId?: string; body: Record; combo: ComboLike; handleSingleModel: HandleSingleModel; diff --git a/open-sse/services/contextManager.ts b/open-sse/services/contextManager.ts index 919c0d1e66..c231759a07 100644 --- a/open-sse/services/contextManager.ts +++ b/open-sse/services/contextManager.ts @@ -281,6 +281,29 @@ export function getTokenLimit( return resolveTokenLimit(provider, model, snapshot).limit; } +/** + * Context window from a known source only: an explicit canonical window, or a + * provider/model-specific `resolveTokenLimit` result. The generic 128000 + * catch-all (`specific: false`) is treated as unknown so combo `min()` does + * not advertise 128k when every real member is larger (#10734). + */ +export function getSourcedTokenLimit( + provider: string, + model: string | null = null, + canonicalWindow?: unknown, + snapshot?: ModelCapabilityResolutionSnapshot | null +): number | undefined { + if ( + typeof canonicalWindow === "number" && + Number.isFinite(canonicalWindow) && + canonicalWindow > 0 + ) { + return canonicalWindow; + } + const resolved = resolveTokenLimit(provider, model, snapshot); + return resolved.specific ? resolved.limit : undefined; +} + /** * Resolve a combo target's token limit without crashing when `parseModel(modelStr)` * returns `provider: null` (model id with no `provider/` prefix). @@ -315,7 +338,7 @@ export function getComboTargetTokenLimit(options: { * name heuristic, curated per-provider default) or only from the generic * catch-all default. */ -function resolveTokenLimit( +export function resolveTokenLimit( provider: string, model: string | null = null, snapshot?: ModelCapabilityResolutionSnapshot | null diff --git a/open-sse/services/cursorApiKeyAuth.ts b/open-sse/services/cursorApiKeyAuth.ts new file mode 100644 index 0000000000..60c3385783 --- /dev/null +++ b/open-sse/services/cursorApiKeyAuth.ts @@ -0,0 +1,198 @@ +/** + * Cursor user API keys (`crsr_…`, minted at cursor.com/dashboard/api) are not + * accepted as a Bearer credential by api2.cursor.sh (401). cursor-agent first + * POSTs the key to `/auth/exchange_user_api_key` and receives a 1-hour session + * JWT (`type: "api_key_token"`); the accompanying refreshToken carries the same + * `exp`, so "refresh" simply means re-exchanging the key. This module owns that + * exchange plus a per-key cache so the executor and the Cursor CLI passthrough + * share one live session token per key. + */ + +import crypto from "node:crypto"; + +export const CURSOR_API_BASE_URL = "https://api2.cursor.sh"; +export const CURSOR_API_KEY_PREFIX = "crsr_"; +export const CURSOR_API_KEY_EXCHANGE_PATH = "/auth/exchange_user_api_key"; +export const CURSOR_API_KEY_EXCHANGE_URL = `${CURSOR_API_BASE_URL}${CURSOR_API_KEY_EXCHANGE_PATH}`; + +const REFRESH_SKEW_MS = 5 * 60 * 1000; +const FALLBACK_TTL_MS = 55 * 60 * 1000; +const EXCHANGE_TIMEOUT_MS = 15_000; + +export type CursorSessionToken = { + accessToken: string; + refreshToken: string | null; + expiresAt: number; +}; + +export class CursorApiKeyExchangeError extends Error { + readonly status: number; + + constructor(message: string, status: number) { + super(message); + this.name = "CursorApiKeyExchangeError"; + this.status = status; + } +} + +type FetchLike = (input: string, init?: RequestInit) => Promise; + +export type CursorApiKeyAuthOptions = { + fetchImpl?: FetchLike; + signal?: AbortSignal; + now?: () => number; +}; + +const sessionCache = new Map(); +const inflightExchanges = new Map>(); + +export function isCursorApiKey(value: unknown): value is string { + return typeof value === "string" && value.startsWith(CURSOR_API_KEY_PREFIX); +} + +function cacheKeyFor(apiKey: string): string { + return crypto.createHash("sha256").update(apiKey).digest("hex"); +} + +export function readJwtExpiryMs(token: string): number | null { + const parts = token.split("."); + if (parts.length !== 3) return null; + try { + const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8")) as { + exp?: unknown; + }; + return typeof payload.exp === "number" && Number.isFinite(payload.exp) + ? payload.exp * 1000 + : null; + } catch { + return null; + } +} + +function parseExchangeBody(raw: string): { accessToken: string; refreshToken: string | null } { + let parsed: unknown; + try { + parsed = JSON.parse(raw); + } catch { + throw new CursorApiKeyExchangeError("Cursor API key exchange returned a non-JSON body", 502); + } + if (!parsed || typeof parsed !== "object") { + throw new CursorApiKeyExchangeError("Cursor API key exchange returned an empty body", 502); + } + const { accessToken, refreshToken } = parsed as { accessToken?: unknown; refreshToken?: unknown }; + if (typeof accessToken !== "string" || accessToken.length === 0) { + throw new CursorApiKeyExchangeError("Cursor API key exchange returned no accessToken", 502); + } + return { + accessToken, + refreshToken: typeof refreshToken === "string" && refreshToken.length > 0 ? refreshToken : null, + }; +} + +export async function exchangeCursorApiKey( + apiKey: string, + options: CursorApiKeyAuthOptions = {} +): Promise { + if (!isCursorApiKey(apiKey)) { + throw new CursorApiKeyExchangeError( + `Cursor API keys start with "${CURSOR_API_KEY_PREFIX}"`, + 400 + ); + } + const fetchImpl = options.fetchImpl ?? fetch; + const now = options.now ?? Date.now; + const signal = options.signal ?? AbortSignal.timeout(EXCHANGE_TIMEOUT_MS); + + let response: Response; + try { + response = await fetchImpl(CURSOR_API_KEY_EXCHANGE_URL, { + method: "POST", + headers: { + authorization: `Bearer ${apiKey}`, + "content-type": "application/json", + accept: "application/json", + }, + body: "{}", + signal, + }); + } catch { + throw new CursorApiKeyExchangeError("Cursor API key exchange request failed", 502); + } + + if (response.status === 401 || response.status === 403) { + throw new CursorApiKeyExchangeError("Cursor rejected the API key", 401); + } + if (!response.ok) { + throw new CursorApiKeyExchangeError( + `Cursor API key exchange failed with HTTP ${response.status}`, + response.status >= 500 ? 502 : response.status + ); + } + + const { accessToken, refreshToken } = parseExchangeBody(await response.text()); + const expiresAt = readJwtExpiryMs(accessToken) ?? now() + FALLBACK_TTL_MS; + return { accessToken, refreshToken, expiresAt }; +} + +function isFresh(token: CursorSessionToken, nowMs: number): boolean { + return token.expiresAt - REFRESH_SKEW_MS > nowMs; +} + +export async function resolveCursorSessionToken( + apiKey: string, + options: CursorApiKeyAuthOptions = {} +): Promise { + const now = options.now ?? Date.now; + const key = cacheKeyFor(apiKey); + const cached = sessionCache.get(key); + if (cached && isFresh(cached, now())) return cached; + + const pending = inflightExchanges.get(key); + if (pending) return pending; + + const exchange = exchangeCursorApiKey(apiKey, options) + .then((token) => { + sessionCache.set(key, token); + return token; + }) + .finally(() => { + inflightExchanges.delete(key); + }); + inflightExchanges.set(key, exchange); + return exchange; +} + +export function invalidateCursorSessionToken(apiKey: string): void { + sessionCache.delete(cacheKeyFor(apiKey)); +} + +export function stripCursorOAuthTokenPrefix(accessToken: string): string { + return accessToken.includes("::") ? accessToken.split("::")[1] : accessToken; +} + +export type CursorBearerCredentials = { + apiKey?: string | null; + accessToken?: string | null; +}; + +export async function resolveCursorBearerToken( + credentials: CursorBearerCredentials, + options: CursorApiKeyAuthOptions = {} +): Promise { + if (isCursorApiKey(credentials.apiKey)) { + const session = await resolveCursorSessionToken(credentials.apiKey, options); + return session.accessToken; + } + if (typeof credentials.accessToken === "string" && credentials.accessToken.length > 0) { + return stripCursorOAuthTokenPrefix(credentials.accessToken); + } + throw new CursorApiKeyExchangeError( + "Cursor connection has neither an API key nor a session token", + 401 + ); +} + +export function __resetCursorApiKeyAuthForTest(): void { + sessionCache.clear(); + inflightExchanges.clear(); +} diff --git a/open-sse/services/taskAwareRouter.ts b/open-sse/services/taskAwareRouter.ts index 8970a60218..e1ba402b3f 100644 --- a/open-sse/services/taskAwareRouter.ts +++ b/open-sse/services/taskAwareRouter.ts @@ -28,6 +28,14 @@ interface TaskPattern { userPatterns?: string[]; // in user message content } +/** + * Per-task-type replacement for the built-in detection patterns (same config surface as + * taskModelMap). A provided `patterns`/`userPatterns` array replaces the built-in list for + * that task type — no merge. Omitting a task type, or a field within it, falls back to + * TASK_PATTERNS. + */ +export type TaskPatternOverrides = Partial>>; + export interface TaskRoutingConfig { enabled: boolean; /** @@ -35,6 +43,8 @@ export interface TaskRoutingConfig { * Empty string = use whatever was requested (no override). */ taskModelMap: Record; + /** Operator-configurable detection patterns — see TaskPatternOverrides. */ + patternOverrides?: TaskPatternOverrides; detectionEnabled: boolean; stats: { detected: number; routed: number }; } @@ -274,6 +284,16 @@ export function getDefaultTaskModelMap(): Record { return { ...DEFAULT_TASK_MODEL_MAP }; } +/** Built-in detection patterns, before any operator patternOverrides — for the settings UI. */ +export function getDefaultTaskPatterns(): Record { + return Object.fromEntries( + Object.entries(TASK_PATTERNS).map(([taskType, { patterns, userPatterns }]) => [ + taskType, + { patterns: [...patterns], ...(userPatterns ? { userPatterns: [...userPatterns] } : {}) }, + ]) + ) as Record; +} + // ── Detection ──────────────────────────────────────────────────────────────── interface RequestMessage { @@ -338,8 +358,13 @@ export function detectTaskType(body: any): TaskType { "creative", ]; + const overrides = getConfig().patternOverrides; + for (const taskType of priorityOrder) { - const { patterns, userPatterns } = TASK_PATTERNS[taskType]; + const defaults = TASK_PATTERNS[taskType]; + const override = overrides?.[taskType]; + const patterns = override?.patterns ?? defaults.patterns; + const userPatterns = override?.userPatterns ?? defaults.userPatterns; // Check system prompt if (patterns.some((p) => systemText.includes(p.toLowerCase()))) { diff --git a/open-sse/services/tokenRefresh.ts b/open-sse/services/tokenRefresh.ts index 6b8b018a04..2ca3c5df62 100755 --- a/open-sse/services/tokenRefresh.ts +++ b/open-sse/services/tokenRefresh.ts @@ -12,6 +12,7 @@ // tests) keep a stable surface. import { AsyncLocalStorage } from "node:async_hooks"; import { PROVIDERS } from "../config/constants.ts"; +import { getCodexAuthIdentityHeaders } from "../config/codexClient.ts"; import { runWithProxyContext } from "../utils/proxyFetch.ts"; import { serializeRefresh } from "./refreshSerializer.ts"; import { @@ -254,6 +255,12 @@ export async function refreshAccessToken( headers: { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json", + // Credential face (auth.openai.com): the real Codex client sends only + // originator + User-Agent here — no version header (that gate exists + // only on the /backend-api/codex inference face). Refreshing with a + // bare/anonymous identity is a half-identity no real client emits. + // Mirrors sub2api v0.1.178 ApplyCodexCanonicalAuthIdentity. + ...(provider === "codex" ? getCodexAuthIdentityHeaders() : null), }, body: params, }) diff --git a/open-sse/services/usage/codex.ts b/open-sse/services/usage/codex.ts index 564cbdad9d..64b37c0183 100644 --- a/open-sse/services/usage/codex.ts +++ b/open-sse/services/usage/codex.ts @@ -9,6 +9,7 @@ */ import { buildCodexUsageQuotas } from "../codexUsageQuotas.ts"; +import { getCodexBackendIdentityHeaders } from "../../config/codexClient.ts"; import { getFieldValue } from "./scalars.ts"; // Codex (OpenAI) API config @@ -36,6 +37,10 @@ export async function getCodexUsage( Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", Accept: "application/json", + // Same UA/version identity chain as Codex inference (sub2api v0.1.178 + // unified-outbound-identity): usage probes must not show up upstream as + // an anonymous half-identity next to the converged inference traffic. + ...getCodexBackendIdentityHeaders(), }; if (accountId) { headers["chatgpt-account-id"] = accountId; diff --git a/open-sse/services/usage/kimi.ts b/open-sse/services/usage/kimi.ts index ca9f2d5630..d27c3c889b 100644 --- a/open-sse/services/usage/kimi.ts +++ b/open-sse/services/usage/kimi.ts @@ -9,12 +9,16 @@ */ import { safePercentage } from "@/shared/utils/formatting"; +import { + KIMI_CODE_ADDITIONAL_CREDITS_URL, + type KimiBillingStatus, +} from "@/shared/utils/kimiBilling"; import { buildKimiCodeIdentityHeaders, getKimiCodeCliUserAgent, } from "../../config/providers/registry/kimi/coding/runtime.ts"; import { toRecord, toNumber } from "./scalars.ts"; -import { type UsageQuota, parseResetTime } from "./quota.ts"; +import { createQuotaFromUsage, type UsageQuota, parseResetTime } from "./quota.ts"; type JsonRecord = Record; @@ -25,6 +29,145 @@ const KIMI_CONFIG = { apiVersion: "2023-06-01", }; +const KIMI_BOOSTER_FIXED_POINT_PER_CENT = 1_000_000; + +function toInteger(value: unknown): number | null { + const parsed = toNumber(value, Number.NaN); + return Number.isFinite(parsed) ? Math.trunc(parsed) : null; +} + +function fixedPointToCents(value: number): number { + const cents = value / KIMI_BOOSTER_FIXED_POINT_PER_CENT; + if (cents > 0 && cents < 1) return 1; + return Math.round(cents); +} + +function parseKimiMoney(value: unknown): { cents: number; currency: string } | null { + const money = toRecord(value); + const cents = toInteger(money.priceInCents); + const currency = money.currency; + if ( + cents === null || + cents < 0 || + typeof currency !== "string" || + !/^[A-Za-z]{3}$/.test(currency) + ) { + return null; + } + return { cents, currency: currency.toUpperCase() }; +} + +function parseKimiExtraUsageStatus(value: unknown): KimiBillingStatus["extraUsageStatus"] { + switch (value) { + case "STATUS_ACTIVE": + return "enabled"; + case "STATUS_DISABLED": + return "disabled"; + case "STATUS_FROZEN": + return "frozen"; + default: + return "unavailable"; + } +} + +function parseKimiBoosterWallet(value: unknown): KimiBillingStatus | null { + const wallet = toRecord(value); + const balance = toRecord(wallet.balance); + if (balance.type !== "BOOSTER") return null; + + const amount = toInteger(balance.amount); + const amountLeft = toInteger(balance.amountLeft); + const monthlyLimit = parseKimiMoney(wallet.monthlyChargeLimit); + const monthlyUsed = parseKimiMoney(wallet.monthlyUsed); + const autoRefillCharge = parseKimiMoney(wallet.autoRefillCharge); + const autoRefillThreshold = parseKimiMoney(wallet.autoRefillThreshold); + const extraUsageStatus = parseKimiExtraUsageStatus(wallet.status); + const hasWalletEvidence = + (amount !== null && amount > 0) || + amountLeft !== null || + monthlyLimit !== null || + monthlyUsed !== null || + extraUsageStatus !== "unavailable"; + if (!hasWalletEvidence) return null; + + const currency = + monthlyLimit?.currency ?? + monthlyUsed?.currency ?? + autoRefillCharge?.currency ?? + autoRefillThreshold?.currency ?? + "USD"; + + return { + currency, + // Proto JSON omits numeric zero values. Production therefore returns a + // BOOSTER balance record without amount/amountLeft when the preserved + // balance is exactly zero; treat that as an explicit zero, not unknown. + extraCreditsMinorUnits: + amountLeft === null || amountLeft < 0 ? 0 : fixedPointToCents(amountLeft), + monthlyUsedMinorUnits: monthlyUsed?.cents ?? 0, + monthlyLimitEnabled: wallet.monthlyChargeLimitEnabled === true, + monthlyLimitMinorUnits: monthlyLimit?.cents ?? 0, + extraUsageStatus, + additionalCreditsUrl: KIMI_CODE_ADDITIONAL_CREDITS_URL, + }; +} + +function buildKimiBillingStatus(value: unknown): KimiBillingStatus { + return ( + parseKimiBoosterWallet(value) ?? { + currency: "USD", + extraUsageStatus: "unavailable", + additionalCreditsUrl: KIMI_CODE_ADDITIONAL_CREDITS_URL, + } + ); +} + +function optionalNumber(value: unknown): number | null { + if (typeof value !== "number" && typeof value !== "string") return null; + const parsed = toNumber(value, Number.NaN); + return Number.isFinite(parsed) ? parsed : null; +} + +function createKimiCountQuota(value: unknown): UsageQuota | null { + const detail = toRecord(value); + const limit = optionalNumber(detail.limit ?? detail.Limit); + if (limit === null || limit <= 0) return null; + + const reportedUsed = optionalNumber(detail.used ?? detail.Used); + const reportedRemaining = optionalNumber(detail.remaining ?? detail.Remaining); + const used = reportedUsed ?? (reportedRemaining === null ? 0 : limit - reportedRemaining); + return createQuotaFromUsage(used, limit, detail.resetTime ?? detail.reset_at ?? detail.resetAt); +} + +type KimiWindowLabel = { key: string; displayName: string }; + +function normalizeKimiWindow(value: unknown, fallbackIndex: number): KimiWindowLabel { + const window = toRecord(value); + const duration = optionalNumber(window.duration); + const timeUnit = window.timeUnit; + + if (duration !== null && duration > 0) { + if (timeUnit === "TIME_UNIT_MINUTE" && duration % 60 === 0) { + const hours = duration / 60; + return { key: `${hours}h`, displayName: `Code · ${hours}h` }; + } + if (timeUnit === "TIME_UNIT_HOUR") { + return { key: `${duration}h`, displayName: `Code · ${duration}h` }; + } + if (timeUnit === "TIME_UNIT_DAY") { + return { key: `${duration}d`, displayName: `Code · ${duration}d` }; + } + if (timeUnit === "TIME_UNIT_WEEK") { + return { key: `${duration}w`, displayName: `Code · ${duration}w` }; + } + if (timeUnit === "TIME_UNIT_MINUTE") { + return { key: `${duration}m`, displayName: `Code · ${duration}m` }; + } + } + + return { key: `limit_${fallbackIndex}`, displayName: `Code · Limit ${fallbackIndex}` }; +} + /** * Map Kimi membership level to display name * LEVEL_BASIC = Moderato, LEVEL_INTERMEDIATE = Allegretto, @@ -100,52 +243,38 @@ export async function getKimiUsage( const quotas: Record = {}; const dataObj = toRecord(data); + const billing = buildKimiBillingStatus(dataObj.boosterWallet); - // Parse Kimi usage response format - // Format: { user: {...}, usage: { limit: "100", used: "92", remaining: "8", resetTime: "..." }, limits: [...] } - const usageObj = toRecord(dataObj.usage); - - // Check for Kimi's actual usage fields (strings, not numbers) - const usageLimit = toNumber(usageObj.limit || usageObj.Limit, 0); - const usageUsed = toNumber(usageObj.used || usageObj.Used, 0); - const usageRemaining = toNumber(usageObj.remaining || usageObj.Remaining, 0); - const usageResetTime = - usageObj.resetTime || usageObj.ResetTime || usageObj.reset_at || usageObj.resetAt; - - if (usageLimit > 0) { - const percentRemaining = usageLimit > 0 ? (usageRemaining / usageLimit) * 100 : 0; - - quotas["Weekly"] = { - used: usageUsed, - total: usageLimit, - remaining: usageRemaining, - remainingPercentage: percentRemaining, - resetAt: parseResetTime(usageResetTime), - unlimited: false, - }; + // The managed Kimi Code API reports the Code 7-day quota in `usage`. + // The website's separate shared-membership total/Kimi split comes from a + // Web-session-only endpoint and cannot be read with a Coding OAuth token. + const weeklyQuota = createKimiCountQuota(dataObj.usage); + if (weeklyQuota) { + quotas.code_7d = { ...weeklyQuota, displayName: "Code · 7d" }; } - // Also parse limits array for rate limits + // Each limits[] item is an independent rolling window. Preserve all of + // them with deterministic window-derived keys instead of overwriting one + // generic `Ratelimit` row. const limitsArray = Array.isArray(dataObj.limits) ? dataObj.limits : []; for (let i = 0; i < limitsArray.length; i++) { const limitItem = toRecord(limitsArray[i]); - const window = toRecord(limitItem.window); - const detail = toRecord(limitItem.detail); + const quota = createKimiCountQuota(limitItem.detail); + if (!quota) continue; - const limit = toNumber(detail.limit || detail.Limit, 0); - const remaining = toNumber(detail.remaining || detail.Remaining, 0); - const resetTime = detail.resetTime || detail.reset_at || detail.resetAt; - - if (limit > 0) { - quotas["Ratelimit"] = { - used: limit - remaining, - total: limit, - remaining, - remainingPercentage: limit > 0 ? (remaining / limit) * 100 : 0, - resetAt: parseResetTime(resetTime), - unlimited: false, - }; - } + const normalized = normalizeKimiWindow(limitItem.window, i + 1); + const baseKey = `code_${normalized.key}`; + let key = baseKey; + let suffix = 2; + while (key in quotas) key = `${baseKey}_${suffix++}`; + const reportedName = + typeof limitItem.name === "string" && limitItem.name.trim() ? limitItem.name.trim() : null; + const displayName = reportedName + ? /^code\b/i.test(reportedName) + ? reportedName + : `Code · ${reportedName}` + : normalized.displayName; + quotas[key] = { ...quota, displayName }; } // Check for quota windows (Claude-like format with utilization) as fallback @@ -189,6 +318,7 @@ export async function getKimiUsage( return { plan: planName || "Kimi Coding", quotas, + billing, }; } @@ -199,6 +329,7 @@ export async function getKimiUsage( return { plan: planName || "Kimi Coding", message: "Kimi Coding connected. Usage tracked per request.", + billing, }; } catch (error) { return { diff --git a/open-sse/translator/request/openai-to-claude.ts b/open-sse/translator/request/openai-to-claude.ts index ff07029e61..8a5c115c2a 100644 --- a/open-sse/translator/request/openai-to-claude.ts +++ b/open-sse/translator/request/openai-to-claude.ts @@ -7,10 +7,17 @@ import { sanitizeToolId } from "../helpers/schemaCoercion.ts"; import { safeParseJSON } from "../helpers/jsonUtil.ts"; import { applyKimiCodingThinking } from "../helpers/claudeHelper.ts"; import { DEFAULT_THINKING_CLAUDE_SIGNATURE } from "../../config/defaultThinkingSignature.ts"; -import { getDefaultThinkingBudget, isAdaptiveThinkingOnly } from "../../../src/shared/constants/modelSpecs.ts"; +import { + getDefaultThinkingBudget, + isAdaptiveThinkingOnly, +} from "../../../src/shared/constants/modelSpecs.ts"; import { fitThinkingToMaxTokens } from "./openai-to-claude/thinkingBudget.ts"; import { enforceToolResultAdjacency } from "./openai-to-claude/toolResultAdjacency.ts"; import { sanitizeToolResultId } from "./openai-to-claude/sanitizeToolResultId.ts"; +import { + openAiImagePartToClaudeBlock, + normalizeToolResultImages, +} from "./openai-to-claude/imageBlocks.ts"; // Reasoning-effort levels Anthropic accepts on `output_config.effort`. Used to steer // adaptive-only Claude models (Opus 4.7+/Fable 5) without ever emitting a manual budget. @@ -534,9 +541,10 @@ function getContentBlocksFromMessage( const sanitizedToolUseId = sanitizeToolResultId(msg.tool_call_id); // #7705 if (!sanitizedToolUseId) return blocks; // T02: Strip empty text blocks from nested tool_result content to avoid Anthropic 400 - const toolContent = Array.isArray(msg.content) - ? stripEmptyTextBlocks(msg.content) - : msg.content; + // #9692: rewrite OpenAI image_url parts to Claude image blocks (same as user turns) + const toolContent = normalizeToolResultImages( + Array.isArray(msg.content) ? stripEmptyTextBlocks(msg.content) : msg.content + ); blocks.push({ type: "tool_result", tool_use_id: sanitizedToolUseId, @@ -555,43 +563,19 @@ function getContentBlocksFromMessage( // Skip tool_result with no tool_use_id (would be useless and may cause errors) if (!part.tool_use_id) continue; // T02: strip empty text blocks from nested content before passing to Anthropic - const resultContent = Array.isArray(part.content) - ? stripEmptyTextBlocks(part.content) - : part.content; + // #9692: convert OpenAI image_url nested in tool_result the same way + const resultContent = normalizeToolResultImages( + Array.isArray(part.content) ? stripEmptyTextBlocks(part.content) : part.content + ); blocks.push({ type: "tool_result", tool_use_id: sanitizeToolId(part.tool_use_id), // #7705 content: resultContent, ...(part.is_error && { is_error: part.is_error }), }); - } else if (part.type === "image_url") { - const url = part.image_url.url; - const match = url.match(/^data:([^;]+);base64,(.+)$/); - if (match) { - blocks.push({ - type: "image", - source: { type: "base64", media_type: match[1], data: match[2] }, - }); - } else if (typeof url === "string" && url.trim()) { - blocks.push({ - type: "image", - source: { type: "url", url }, - }); - } - } else if (part.type === "image" && part.source) { - blocks.push({ type: "image", source: part.source }); - } else if (part.type === "image" && typeof part.image === "string") { - // AI SDK-style image part: { type: "image", image: "data:...;base64,..." } (#1330) - const url = part.image; - const match = url.match(/^data:([^;]+);base64,(.+)$/); - if (match) { - blocks.push({ - type: "image", - source: { type: "base64", media_type: match[1], data: match[2] }, - }); - } else if (url.trim()) { - blocks.push({ type: "image", source: { type: "url", url } }); - } + } else if (part.type === "image_url" || part.type === "image") { + const imageBlock = openAiImagePartToClaudeBlock(part); + if (imageBlock) blocks.push(imageBlock); } else if (part.type === "file" && (part.file?.file_data || part.file?.data)) { // OpenAI Chat Completions file block: // {type:"file", file:{filename, file_data:"data:;base64,..."}}. diff --git a/open-sse/translator/request/openai-to-claude/imageBlocks.ts b/open-sse/translator/request/openai-to-claude/imageBlocks.ts new file mode 100644 index 0000000000..3157c500fa --- /dev/null +++ b/open-sse/translator/request/openai-to-claude/imageBlocks.ts @@ -0,0 +1,77 @@ +/** + * Convert OpenAI-style image parts (including those nested in tool results) + * into Claude Messages `image` blocks. User-message `image_url` already did + * this; `role: "tool"` and nested `tool_result` content previously forwarded + * the OpenAI shape unchanged, which Anthropic rejects with HTTP 400 (#9692). + */ + +const DATA_URL_RE = /^data:([^;]+);base64,(.+)$/; + +type ClaudeImageBlock = { + type: "image"; + source: { type: "base64"; media_type: string; data: string } | { type: "url"; url: string }; +}; + +export function extractOpenAiImageUrl(imageUrl: unknown): string { + if (typeof imageUrl === "string") return imageUrl; + if (imageUrl && typeof imageUrl === "object" && !Array.isArray(imageUrl)) { + const url = (imageUrl as { url?: unknown }).url; + if (typeof url === "string") return url; + } + return ""; +} + +export function urlToClaudeImageBlock(url: string): ClaudeImageBlock | null { + if (typeof url !== "string") return null; + const trimmed = url.trim(); + if (!trimmed) return null; + const match = trimmed.match(DATA_URL_RE); + if (match) { + return { + type: "image", + source: { type: "base64", media_type: match[1], data: match[2] }, + }; + } + return { type: "image", source: { type: "url", url: trimmed } }; +} + +/** + * Map one OpenAI / AI-SDK image-shaped part to a Claude image block. + * Returns null when the part is not an image (caller should keep it as-is). + */ +export function openAiImagePartToClaudeBlock( + part: Record +): ClaudeImageBlock | null { + const type = part.type; + if (type === "image_url") { + return urlToClaudeImageBlock(extractOpenAiImageUrl(part.image_url)); + } + if (type === "image") { + if (part.source && typeof part.source === "object" && !Array.isArray(part.source)) { + return { type: "image", source: part.source as ClaudeImageBlock["source"] }; + } + if (typeof part.image === "string") { + return urlToClaudeImageBlock(part.image); + } + } + return null; +} + +/** + * Walk a tool_result content value and rewrite OpenAI `image_url` (and AI-SDK + * `image`) parts to Claude `image` blocks. Nested `tool_result` arrays recurse. + * Non-array content (plain strings) is left unchanged. + */ +export function normalizeToolResultImages(content: unknown): unknown { + if (!Array.isArray(content)) return content; + return content.map((block) => { + if (!block || typeof block !== "object" || Array.isArray(block)) return block; + const rec = block as Record; + const image = openAiImagePartToClaudeBlock(rec); + if (image) return image; + if (rec.type === "tool_result" && Array.isArray(rec.content)) { + return { ...rec, content: normalizeToolResultImages(rec.content) }; + } + return rec; + }); +} diff --git a/package.json b/package.json index 64d600aa04..5a235fec3b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "omniroute", "version": "3.8.50", - "description": "Unified AI router with 341 providers, RTK+Caveman compression, auto fallback, MCP/A2A, desktop, PWA, and OpenAI-compatible APIs.", + "description": "Unified AI router with 342 providers, RTK+Caveman compression, auto fallback, MCP/A2A, desktop, PWA, and OpenAI-compatible APIs.", "type": "module", "bin": { "omniroute": "bin/omniroute.mjs", diff --git a/src/app/(dashboard)/dashboard/combos/page.tsx b/src/app/(dashboard)/dashboard/combos/page.tsx index 5cf1c76784..f456d8c6d9 100644 --- a/src/app/(dashboard)/dashboard/combos/page.tsx +++ b/src/app/(dashboard)/dashboard/combos/page.tsx @@ -1440,6 +1440,33 @@ function ComboUsageGuide({ onHide, onHideForever, onCreateCombo }) { })} +
+

+ {getI18nOrFallback(t, "usageGuideInvokeTitle", "How to call this combo")} +

+

+ {getI18nOrFallback( + t, + "usageGuideInvokeDesc", + 'Send the combo\'s exact name as the model, e.g. model: "my-combo" (or combo/my-combo).' + )} +

+

+ {getI18nOrFallback( + t, + "usageGuideInvokeAutoNote", + "auto and auto/* are a separate zero-config router that does not use your combos (unless a combo is literally named auto)." + )} +

+

+ {getI18nOrFallback( + t, + "usageGuideInvokeOpenrouterNote", + "openrouter/auto is a real paid OpenRouter product (Auto Best Available), not an OmniRoute alias — exclude it via Settings → Routing → Hide paid models." + )} +

+
+
Claude Code
- Claude Code + کد Claude

⭐ 67.3K
Kilo Code
- Kilo Code + کد کیلو

⭐ 15.5K