Compare commits

..

113 Commits

Author SHA1 Message Date
Markus Hartung
a582bef675 board #11389 2026-08-24 23:21:27 -03:00
Markus Hartung
f77254da79 board #11443
# Conflicts:
#	README.md
#	docs/diagrams/cli-terminal.svg
#	docs/diagrams/promise-pillars.svg
2026-08-24 23:21:17 -03:00
Markus Hartung
b1474b992f board #11441 2026-08-24 23:20:55 -03:00
Markus Hartung
86514aa481 board #11423 2026-08-24 23:20:52 -03:00
Markus Hartung
a150c6bc40 board #11409 2026-08-24 23:20:49 -03:00
Markus Hartung
c59661cfd6 board #11340 2026-08-24 23:20:47 -03:00
Markus Hartung
b76866fa12 chore(deps): regenerate package-lock.json after ESLint 10 + bun 1.4.0 bump (#11259) 2026-08-24 23:20:22 -03:00
backryun
8a14cefcb1 chore(deps): refresh runtimes and adopt ESLint 10 2026-08-24 23:15:54 -03:00
oyi77
158fb1a806 test(executors): adapt remaining 35 suites to the async lazy registry (round 2)
Round 1 only covered suites importing from executors/index.ts directly;
suites importing getExecutor through other paths (open-sse root
re-export, dynamic imports inside tests) still called it synchronously,
producing Promise-vs-instance assertion failures in CI (e.g.
providers-yuanbao-web 'instanceof YuanbaoWebExecutor' false).

Sweep method: repo-wide scan for un-awaited getExecutor call sites,
adapted mechanically (await + async callbacks + Response|{response}
union narrowing); assert.rejects guards with promise-returning
callbacks verified correct as-is.

Locally verified green: providers-yuanbao-web, ninerouter-executor,
provider-request-failure-pipeline, provider-limits-accesstoken-fallback,
executor-registry, chatcore-executor-proxy, poe-api-executor-regression,
web-cookie-providers-new (113/113).
2026-08-24 21:44:23 -03:00
oyi77
77ea656b12 perf(executors): lazy-load the executor registry — defer class imports + construction to first use (#11220)
The executor barrel statically imported ~100 executor modules and
constructed every instance at module load. Measured cold cost on top of
the minimal set: ~0.7–1.2s boot time and ~35MB heap, paid by every
deployment regardless of which providers it uses.

Now:
- executors/index.ts keeps the declarative alias table byte-stable (same
  keys, same order, same ctor args — pinned by the golden lock) but each
  value is a deferred loader using dynamic import; bundlers emit
  on-demand chunks
- registry.ts gains registerLazyExecutor/loadRegisteredExecutor: aliases
  are declared eagerly so hasSpecializedExecutor() and
  listExecutorAliases() stay synchronous, instances materialize once on
  first use and cache into the same registry map
- getExecutor() becomes async; production call sites (chatCore proxy
  resolver, video generation, compression judge/eval clients,
  quotaAutoPing deps, anthropic OAuth validation) await it
- cliproxy wrapper ExecutorLike types drop their index signatures so
  BaseExecutor satisfies them structurally

Measured after (isolated DATA_DIR): barrel boot 712-832ms / ~45MB with
first-use materialization of an executor costing +120-150ms once.

Test impact: 24 unit suites adapted mechanically to the async seam
(await + union narrowing on the Response | {response} execute result);
class imports moved from the barrel to executor module files. The
web-cookie sweep SIGABRT failure is pre-existing (reproduced identically
on the clean base).

Commit gate note: husky lint-staged fails with 'suppressions left that
do not occur anymore' — reproduced identically on a stashed clean tree
(22 baseline problems), independent of this change.
2026-08-24 21:44:22 -03:00
Minxi Hou
471052b904 fix(combo): enable genuine quota-aware routing for generic providers (antigravity, claude, etc.) 2026-08-24 21:44:06 -03:00
Rouzbeh
b8553c8f0d fix(ci): prune stale ESLint suppressions fixed by this change
Our PR fixed the last no-restricted-imports violation in
src/lib/memory/embedding/index.ts (localDb barrel import replaced by a
direct readCache import), so the frozen suppression entry for that file
became stale. The gate (run-eslint-json.mjs) hard-fails on stale entries,
so remove it to keep 'No new ESLint warnings' green.
2026-08-24 21:44:05 -03:00
Rouzbeh
1255b5869b fix(memory): list and serve embedding/rerank models from all configured providers
The memory Engine tab quick-select built its model list only from a
keyword heuristic over the chat catalog plus OpenRouter live discovery,
so configured providers whose embedding models are not in that catalog
(e.g. Cloudflare Workers AI cf/@cf/baai/bge-m3) never appeared, and
requests for them failed with 'Unknown embedding provider'.

- add cloudflare-ai to EMBEDDING_PROVIDERS with a requiresAccountId URL
  template resolved per-request via buildEmbeddingProviderUrl() (mirrors
  CloudflareAIExecutor on the chat side) plus the cf provider alias
- merge curated registry models into the quick-select catalog and add a
  generic fallback listing: any configured OpenAI-compatible chat
  provider without a curated entry appears with free-text model input
- same treatment for rerank: listRerankProviders + generic Cohere-
  compatible fallback, new /api/memory/rerank-providers endpoint,
  selectors fall back to free-text when no static models exist
- runtime: embeddings service/handler and rerank route/handler resolve
  derived providers instead of rejecting unlisted ones
2026-08-24 21:44:00 -03:00
kriptoburak
ea2746e594 docs(changelog): add Xquik search fragment 2026-08-24 21:43:50 -03:00
kriptoburak
c264c24de9 fix(search): sync generated inference skill 2026-08-24 21:43:50 -03:00
kriptoburak
15cbc1ede7 fix(search): document API and update dispatch golden 2026-08-24 21:43:50 -03:00
kriptoburak
a65666519d feat(search): add Xquik X search provider 2026-08-24 21:43:50 -03:00
Ravi Tharuma
829634b741 fix(i18n): align Brazilian Portuguese resilience keys 2026-08-24 21:43:37 -03:00
Ravi Tharuma
09666c50e7 fix(i18n): keep Vietnamese resilience keys aligned 2026-08-24 21:43:36 -03:00
Ravi Tharuma
2b9f25accb feat(resilience): add hierarchical concurrency admission 2026-08-24 21:43:36 -03:00
WebPerson
9dc7711dc2 fix(electron): make the packaged Windows build pass the #7592 cold-restart smoke
Five defects found while validating #7592 on a real packaged Windows build:

- optionalPackStaging: GNU tar reads the drive letter in an absolute
  -f C:\... archive path as a remote rsh host (Cannot connect to C:),
  failing optional-pack staging on Git-for-Windows machines. Pass a
  bare filename with cwd at the tarball directory; surface tar stderr.
- electron/package.json: lib/loginHeaderCapture.js was missing from the
  asar files allowlist; loginManager.js requires it top-level, so the
  packaged main process crashed on launch.
- electron-builder >=26 injects !**/node_modules/** into every
  extraResources pattern list and no positive filter can override it,
  silently dropping the staged runtime node_modules (including the
  better-sqlite3 N-API prebuild) from resources/app. Add an afterPack
  hook (scripts/build/afterpack-copy-node-modules.mjs) that restores it.
- smoke harness: Electron resolves userData from
  %USERPROFILE%/AppData/Roaming/<name> (USERPROFILE wins over APPDATA)
  and the path service throws when it is missing, so
  requestSingleInstanceLock() returned false and the app exited(0)
  silently before whenReady. ensureSmokeEnvDirs now pre-creates the
  derived tree and is exported for tests.
- core.ts: the #7592 guard parses a [DB] Driver: ... line that only the
  unused openDatabaseAsync() emitted; getDbInstance() now logs the same
  line on its primary open so the assertion is reachable.

Also makes the smoke env-allowlist unit test host-agnostic (it
hardcoded POSIX paths) and adds regression tests for the USERPROFILE
derived tree and tarPack under Windows-style absolute paths.

Closes #7592
2026-08-24 18:06:06 -05:00
Max
42c209797c fix(free-models): stop reporting discontinued Pollinations models as free
The shared isFreeModel() predicate ignored each catalog entry's
freeType, so Pollinations models marked "discontinued" (moved behind a
paid key) were still reported free and could be routed under
hidePaidModels.

Add a compiler-checked grantsFreeAccess(freeType) table and use it in
both the routing predicate and strictZeroCostFilter.

Tests: tests/unit/autoCombo/free-regime-not-read-by-predicate.test.ts
2026-08-25 01:03:45 +02:00
Diego Rodrigues de Sa e Souza
8bbe92c692 fix(docker): size the Next build worker pool for a 16 GB runner (#11419)
Every "Publish to Docker Hub" run has failed since 2026-08-22 23:14 UTC — 96 of
the last 100. The builder stage dies with:

  ERROR: failed to solve: ResourceExhausted: process "/bin/sh -c ... npm run
  build ..." did not complete successfully: cannot allocate memory

That is the kernel, not V8. The log puts it precisely: the compile phase always
finishes ("✓ Compiled successfully in 4.2min") and the build is killed right
after "Collecting page data using 7 workers".

Each page-data worker is its own process and inherits NODE_OPTIONS, so the
--max-old-space-size ceiling is per PROCESS, not per build. CIRCLE_NODE_TOTAL=8
means 7 workers, and 7 of them alongside the parent no longer fit the 16 GB /
4 vCPU GitHub-hosted runners the pipeline builds on. It was intermittent for a
while before going 100%, which is what a threshold crossed by ordinary codebase
growth looks like — 7 was also oversubscribing a 4 vCPU runner.

Lower the pool to 3 (2 workers) and make it a build arg, so a big builder can
raise it back with `--build-arg OMNIROUTE_BUILD_WORKERS=8`.

tests/unit/docker-build-memory-budget.test.ts pins the budget: it reads the two
ARG defaults out of the Dockerfile and fails if `parent heap + workers × peak`
outgrows the runner, or if the pool oversubscribes its CPUs. Red on the base
(3/3), green here (3/3). The per-worker peak it budgets with is documented as an
inference from this failure, not a measurement.

DOCKER_GUIDE's build-arg table was stale (it still listed the pre-#10060 4096 MB
default); updated and given the new knob plus the symptom to recognize.
CIRCLE_NODE_TOTAL and OMNIROUTE_BUILD_WORKERS are allowlisted in the
fabricated-docs gate with the reason: neither is read via process.env here — one
is a Dockerfile ARG, the other is read by Next itself.

Note: the real proof is the next publish run. This failure mode only reproduces
on a memory-constrained host, so it cannot be reproduced by the unit suite; the
test guards the arithmetic, not the outcome.

Co-authored-by: Xiangzhe <bakryun0718@proton.me>
2026-08-24 15:47:47 -03:00
Diego Rodrigues de Sa e Souza
bbc7bf4351 fix(authz): match exact public routes exactly, not as prefixes (#11417)
`isPublicApiRoute()` matched every entry of PUBLIC_API_ROUTE_PREFIXES with
`startsWith()`, but 11 of the 15 entries name ONE route, not a subtree. As a
prefix each also marked every adjacent path sharing its leading characters as
PUBLIC, which skips the MANAGEMENT auth gate.

That is reachable today: Next resolves `/api/usage/om-usage<anything>` to the
dynamic route `/api/usage/[connectionId]`, and that handler carries no auth of
its own — it relies entirely on being classified MANAGEMENT. An unauthenticated
caller therefore reaches `fetchAndPersistProviderLimits()`, which is an
existence oracle over connection ids (409/404/400/200) and, for a connection id
actually starting with `om-usage`, discloses live quota JSON and can drive an
OAuth token refresh (a write side effect) with no credentials.

Split the allowlist by shape:

- PUBLIC_API_ROUTE_PREFIXES keeps only genuine subtrees, every entry ending in
  "/" (asserted by a unit test, so the class cannot come back silently).
- PUBLIC_API_ROUTES_EXACT holds the single routes, matched exactly in both
  spellings.
- The three read-only "prefixes" were single routes too and move to
  PUBLIC_READONLY_CORS_API_ROUTES, matched exactly. classify.ts now asks
  `isPublicReadonlyCorsRoute()` instead of scanning the raw list, so the CORS
  origin relaxation pipeline.ts keys on cannot be inherited by a sibling either
  (`/api/monitoring/health-detail` was taking it).
- `/api/health` deliberately stays in its own set so it keeps classifying as
  `public_prefix`; folding it into the read-only set would widen CORS on it.

dashboardCsrf.ts had a second copy of the prefix scan; it now shares
`isPublicApiRoute()` so the client CSRF exemption and the server classification
cannot disagree. Side effect in the safe direction: the three LOCAL_ONLY oauth
auto-import routes were CSRF-exempt on the client while the server already
required the token — the client now attaches it.

Reported by @ntdat812 (GHSA-74g9-q8f6-793h), with the shape of the fix and the
two gotchas above called out in the report.

Closes GHSA-74g9-q8f6-793h

Co-authored-by: Xiangzhe <bakryun0718@proton.me>
Co-authored-by: Nguyen Thanh Dat <ntdat812.dev@gmail.com>
2026-08-24 15:47:34 -03:00
oyi77
38527e4a21 docs(design): external durable-state DB backend proposal (#8075)
Grounded design answering the five open questions in #8075 with a
measured coupling census of release/v3.8.51: 126 db modules on the sync
prepare()/transaction() shape, 36 pragma sites, 159 SQLite migrations,
9 sqlite-vec + 8 FTS5 files, and a 4-driver SqliteAdapter seam that is
SQLite-only in practice (synchronous API).

Proposal: dialect-agnostic async DurableStateStore port with per-domain
repositories adopted incrementally; Postgres-first with MySQL gated by
a shared dialect-conformance suite; DATABASE_DRIVER config surface with
sqlite as the non-negotiable zero-config default; fail-closed one-way
export tool; five-phase delivery plan.
2026-08-25 01:08:36 +07:00
Jacob Stoner
56d64e29a4 fix(dashboard): expose custom mode-pack option (#11407)
Validado em lote combinado (batch-0824f, junto de #11399/#11400/#11402) contra o tip de release/v3.8.50: typecheck:core limpo, file-size/changelog/complexity/cognitive-complexity OK, 56/56 testes focados passando incluindo os deste PR (tests/unit/autocombo-unification.test.ts).

Baixo risco: expõe a opção "custom" já suportada em runtime (`getModePack("custom") === undefined`, cai de volta para os pesos explícitos dos sliders) no seletor compartilhado de mode-pack da UI. Obrigado pela contribuição!
2026-08-24 14:16:37 -03:00
Jacob Stoner
7b36e45df8 fix(dashboard): normalize explicit auto weights (#11402)
Validado em lote combinado (batch-0824f, junto de #11399/#11400/#11407) contra o tip de release/v3.8.50: typecheck:core limpo, file-size/changelog/complexity/cognitive-complexity OK, 56/56 testes focados passando incluindo os deste PR (tests/unit/combo-scoring-inspector.test.ts).

Baixo risco: normaliza pesos parciais/não-unitários no inspector de diagnóstico (`comboScoringInspector.ts`) reutilizando o normalizador já existente do motor real de scoring, mantendo diagnósticos consistentes com o runtime. Obrigado pela contribuição!
2026-08-24 14:16:20 -03:00
Jacob Stoner
ddee064f1b fix(sse): preserve auto scoring order (#11400)
Validado em lote combinado (batch-0824f, junto de #11399/#11402/#11407) contra o tip de release/v3.8.50: typecheck:core limpo, file-size/changelog/complexity/cognitive-complexity OK, 56/56 testes focados passando incluindo os deste PR (tests/unit/combo-task-aware.test.ts).

Remove `auto` da lista de estratégias task-routing genéricas — coerente com o #11399, que também protege a ordem já computada pelo `auto` contra reordenação por outro pós-processamento. Obrigado pela contribuição!
2026-08-24 14:16:04 -03:00
Jacob Stoner
b1fdfd5ea4 fix(sse): preserve auto-selected first target (#11399)
Validado em lote combinado (batch-0824f, junto de #11400/#11402/#11407) contra o tip de release/v3.8.50: typecheck:core limpo, file-size/changelog/complexity/cognitive-complexity OK (abaixo do baseline), 56/56 testes focados passando incluindo os deste PR (tests/unit/8370-priority-affinity-reorder.test.ts).

Aditivo e coerente: protege a ordem já decidida pelo `auto` contra reordenação pelo pós-processamento de prompt-cache-affinity — mesma linha do #11400. Obrigado pela contribuição!
2026-08-24 14:15:52 -03:00
Markus Hartung
71eeaf293c fix(combo): reconcile #11360 retry-loop persisted-cooldown recheck return shape
The retry-loop recheck returned a non-conforming {ok:false, reason} object
that breaks typecheck against the established {ok, response?} contract used
everywhere else in this function. Aligns with the pre-dispatch skip pattern
(return null after fallbackCount++), matching the PR's own intent: skip this
target and move to the next, not error the whole attempt.

This is a live fix — the broken shape reached origin/release/v3.8.50 via
#11360's own squash-merge and was breaking typecheck:core until now.
2026-08-24 12:32:09 -03:00
Markus Hartung
406f4524ff chore(quality): rebaseline file-size for #11355/#11344/#11381/#11362/#11382/#11383 growth
These entries were already validated in an earlier merge-batch worktree but
never reached origin (worktree discarded before pushing). Re-adding them
here since #11355's test/route.ts growth (1215->1237) is now live on
origin/release/v3.8.50 and fails the frozen cap otherwise.
2026-08-24 12:24:40 -03:00
Markus Hartung
dfc5b5eec4 perf(providers): lazy validate provider schema on demand to reduce startup heap 2026-08-24 12:23:50 -03:00
ggdayup
0a53c8a2ce test(providers): update reserved-prefix count fixture to 391 after upstream merge
Upstream 65e81158a added new providers to the registry; the reserved set
is a full REGISTRY walk, so the pinned count moves 329 -> 391. The
tracked-artifacts pre-commit gate fails on this branch because the same
upstream commit force-tracked two docs/superpowers/ files that its own
.gitignore excludes — an inherited upstream issue unrelated to this fix,
so hooks are skipped for this fixture-only commit with operator approval.
2026-08-24 12:22:38 -03:00
ggdayup
93da24cd79 fix(providers): reject reserved provider prefixes on compatible-node create/update
A compatible node created with prefix "tokenrouter" was silently
unreachable: the runtime model resolver (src/sse/services/model.ts)
skips compatible-node lookup for built-in registry ids/aliases, so
"tokenrouter/qwen/..." routed to the built-in tokenrouter provider and
failed with "No active credentials for provider: tokenrouter" even
though the node itself worked when addressed by its internal id.

Reject reserved prefixes at the write path instead:

- new shared module src/shared/constants/reservedProviderPrefixes.ts
  (REGISTRY ids + aliases, case-sensitive, built lazily) — single
  source of truth consumed by both the runtime guard and the
  validation schemas so they can never drift apart
- createProviderNodeSchema / updateProviderNodeSchema now reject
  reserved prefixes with a clear message naming the colliding prefix
- src/sse/services/model.ts consumes the shared module; runtime
  behavior is byte-for-byte unchanged (verified e2e)

Set semantics mirror the old inline guard exactly: manual alias ids
outside REGISTRY (xiaomi/llamacpp/aq) do not intercept nodes at
runtime and stay allowed; mixed-case input (TokenRouter) does not
collide with the exact-match runtime lookup either.
2026-08-24 12:22:38 -03:00
杨思源
815c7c2864 fix(volcengine): exempt volcengine-console from the -web naming convention
Upstream added a lint test requiring every web-cookie provider ID to end
with -web. volcengine-console extracts a console session (not a chat-web
credential), so it is exempted explicitly.
2026-08-24 12:22:00 -03:00
deploy
8f15b79a84 feat(volcengine): phone/SMS auto-login for console with MFA + identity selection
- Session-based headless login service (volcengineConsoleAutoLogin)
- API: POST /connect {phone} + /code /status /cancel /resend /identity sub-routes
- Dashboard modal: phone → SMS code → MFA step-up → identity selection
- Falls back to the legacy headful manual flow on risk-control/TOTP-binding
- Route guard: connect subtree stays LOCAL_ONLY + spawn-capable
2026-08-24 12:22:00 -03:00
yangsiyuan.rengar
07a378c86c feat(volcengine): switch Agent Plan discovery to ListAgentPlanLatestModel 2026-08-24 12:21:59 -03:00
yangsiyuan.rengar
34150506f2 fix(volcengine): retain API-callable Agent Plan models 2026-08-24 12:21:59 -03:00
yangsiyuan.rengar
76ac1c8b7e feat(volcengine): live model discovery for Ark plan providers
Replace the static curated model lists for volcengine-agent-plan and
volcengine-coding-plan with live discovery from the console APIs
(GetAgentPlanModelMappingMeta / ListArkCodeLatestModel), authenticated by
the console cookie+csrf already captured at plan binding time.

- Add volcenginePlanModelDiscovery.ts: fetch + parse + capability enrichment
  (family->contextLength/vision/reasoning map, conservative default fallback).
  Console calls go through a dynamic undici import to bypass OmniRoute's
  global fetch patch (built for LLM provider traffic, reroutes console hits).
  Coding plan's ListArkCodeLatestModel needs {AccountId:<number>} extracted
  from the console cookie; agent plan's GetAgentPlanModelMappingMeta filters
  PlatformAllowStatus===true && Type==='llm'.
- Remove both plan ids from CURATED_MODEL_ONLY_PROVIDERS so synced models
  merge into /v1/models and the dashboard Sync Models button works.
- sync-models route: short-circuit to console discovery for plan providers
  (the chat API has no /models endpoint); persist via
  replaceSyncedAvailableModelsForConnection.
- volcenginePlanBinding: set autoSync:true on new plan connections so the
  24h modelSyncScheduler refreshes them automatically.
- volcPlanAutoSyncBackfill: idempotent boot-time backfill so pre-existing
  plan connections also enter the scheduler.

Verified end-to-end on local OmniRoute build against live Volcano console:
agent plan synced 7 LLMs, coding plan synced 11 models, /v1/models exposes
all of them (incl. new glm-5-3-260801 / deepseek-v4-flash-260801).
2026-08-24 12:21:59 -03:00
yangsiyuan.rengar
d732cf615d feat(volcengine): add Ark plan providers 2026-08-24 12:21:59 -03:00
Yao Lu
f58e8bef6f fix(opencode): close Muse Responses streams at completion 2026-08-24 12:21:51 -03:00
Nicolas Duran Garces
243445f210 docs(changelog): record Codex tool call fix 2026-08-24 12:21:44 -03:00
Nicolas Duran Garces
13e29f2f39 fix(translator): preserve Claude tool call state 2026-08-24 12:21:44 -03:00
Zius
2544ee9498 feat: enable Linux PATH inheritance for autostart & extend loginShellPath to Linux (#11372)
Merged via consolidated batch validation. Fixes autostart on Linux failing to inherit the user's shell PATH (CLI-dependent features like Kiro's Google OAuth broke). Resolved a conflict against a batch sibling in bin/cli/commands/doctor.mjs (kept the more complete prebuilds-aware candidate list) and setup-claude.mjs (formatting only). Own test (login-shell-path-3321.test.ts, 10/10) passes + typecheck:core clean. Thanks!
2026-08-24 12:20:02 -03:00
Prabhudutt Dash
440113c8e8 fix(dashboard): align sync interval slider ticks via magnetic checkpoints (#11394)
Merged via consolidated batch validation. Model Database sync-interval slider used two incompatible coordinate systems (evenly spaced labels vs a linear 1-168h scale); moves the slider to checkpoint-space so the thumb and labels agree. Own test passes.
2026-08-24 12:13:45 -03:00
Bob.Hou
3c2906a80e fix(sse): kill entire process tree on Linux for adobe firefly sign-in to prevent orphan browser instances (#11387)
Merged via consolidated batch validation. Fixes orphaned browser processes on Linux for Adobe Firefly sign-in: spawns Chrome as a process-group leader (detached:true) and kills -pid instead of the single PID, with self-termination guards. Own test passes.
2026-08-24 12:13:40 -03:00
Bob.Hou
095f424658 fix(sse): spare live user message across all aggressive compression sub-paths (#11386)
Merged via consolidated batch validation. Aggressive compression could collapse the live user's active prompt into a [COMPRESSED:summary] marker; now spares the last user message across all sub-paths (applyAging, fallback summarizer, caveman/lite). Own test passes.
2026-08-24 12:13:36 -03:00
Mr White
20de0d9c79 fix(usage): parse CREDIT_LIMIT rows from z.ai coding-plan quota API (#11378)
Merged via consolidated batch validation. Z.ai's quota API now returns CREDIT_LIMIT rows for GLM Coding Plan subscription keys instead of TOKENS_LIMIT, breaking the dashboard quota card. Own test passes.
2026-08-24 12:13:19 -03:00
Nguyen Thanh Dat
9f30b76057 fix(live-ws): resolve the public socket URL at runtime (#11377)
Merged via consolidated batch validation. Fixes live-ws public socket URL resolution for prebuilt Docker/npm images, where NEXT_PUBLIC_* is inlined at build time and can never carry an operator's runtime value. Own test passes.
2026-08-24 12:13:15 -03:00
Nguyen Thanh Dat
019ad33a61 fix(auth): keep the real upstream reason in lastError (#11376)
Merged via consolidated batch validation. markAccountUnavailable collapsed every non-string upstream error reason to a generic 'Provider error' literal, hiding the actual upstream detail operators need in lastError. Own test passes.
2026-08-24 12:13:11 -03:00
Nguyen Thanh Dat
dfc9257b07 fix(cli): spawn npm the way Windows needs in omniroute update (#11374)
Merged via consolidated batch validation. Fixes omniroute update on Windows (npm.cmd cannot be execFile'd without a shell on Node >=24, nodejs/node#52554). Extracts a shared bin/cli/npm-exec.mjs (also handles Bun, windowsHide) mirroring the existing server-side pattern in src/lib/services/installers/utils.ts. Own tests pass. Note: #11336 fixed the same underlying bug (#11335) with a narrower inline change; closed as duplicate crediting this more complete fix.
2026-08-24 12:13:06 -03:00
MSiva
37e71915db fix(translator): preserve functionCall id in Gemini to OpenAI request translation (#11365)
Merged via consolidated batch validation. Fixes geminiToOpenAIRequest discarding functionCall.id in favor of a random generated id, causing multi-turn tool-call id mismatches against OpenAI-compatible upstreams. Own test passes.
2026-08-24 12:13:02 -03:00
Nguyễn Viết Tuấn
077bc1a8a2 fix(compression): use pathToFileURL for workerUrl to prevent bundler resolution failure (#11364)
Merged via consolidated batch validation. Fixes Webpack/Turbopack production build failure (Module not found: compressionWorker.js) by using pathToFileURL(join(...)) instead of new URL(..., import.meta.url), which static bundler scanning misidentifies as an asset import.
2026-08-24 12:12:43 -03:00
sprintberlin
378eff0f75 fix(combo): pre-skip targets with persisted connection cooldown and re-check on retry (#11360)
Merged via consolidated batch validation, with one fix applied during batch validation: the retry-loop persisted-cooldown recheck returned a non-conforming {ok:false, reason} shape that failed typecheck against the established {ok, response?} contract — aligned it with the pre-dispatch skip pattern (return null after fallbackCount++), matching this PR's own intent (skip the target, don't error the whole attempt). Pre-skips combo targets with a persisted connection cooldown and re-checks fresh before transient retries. Own regression suite (13/13, including the fixed retry-recheck path) passes.
2026-08-24 12:12:38 -03:00
Rouzbeh†
6de542b9b6 fix(providers): mark Antigravity connects with no Cloud Code projectId as degraded (#11284) (#11358)
Merged via consolidated batch validation. Production evidence (VPS docker instance): Antigravity OAuth connects ending without a Cloud Code projectId were persisted as silently active while every model call failed; now persisted as degraded. Own tests pass.
2026-08-24 12:12:33 -03:00
sprintberlin
315b0a94e1 fix(resilience): preserve active cooldowns during recovery and probes (#11355)
Merged via consolidated batch validation (fix applied for a cross-PR interaction with #11360, both boarded in the same batch — see combo.ts reconciliation commit). Startup crash recovery cleared every non-terminal transient cooldown unconditionally, erasing legitimate multi-day weekly quota cooldowns on restart. Now only clears expired/unparseable ones. Own repro tests pass.
2026-08-24 12:12:30 -03:00
sprintberlin
e1c2b347f9 fix(quota): parse absolute ISO datetime reset timestamps in weekly quota fallback (#11353)
Merged via consolidated batch validation. Fixes GLM/Z.AI weekly quota fallback: parseDayGranularityResetMs only recognized 'reset in N days', dropping the real multi-day cooldown when upstream returns a full absolute ISO datetime. Own repro test passes.
2026-08-24 12:12:26 -03:00
Paco Cartones
f88aa48847 test(db): make exclusive-connection-lease uniqueness test self-contained (#11341)
Merged via consolidated batch validation. Test-only fix: exclusive-connection-lease uniqueness test implicitly depended on lease state from an earlier test in the same file (shared DB instance, reset only in test.after) — now self-contained. No production change.
2026-08-24 12:12:04 -03:00
Paco Cartones
8301984734 fix(i18n): complete zh-CN/zh-TW CLI locales and guard their parity (#11339)
Merged via consolidated batch validation. Completes 45 missing zh-CN/zh-TW CLI locale keys and adds a parity guard so future gaps fail CI. Own tests pass.
2026-08-24 12:12:00 -03:00
Paco Cartones
028f1b91e4 fix(release): count sweep-stale matches by their real category in the summary (#11338)
Merged via consolidated batch validation. Fixes sweep-stale-fragments.mjs miscounting: classifyFragments never actually produces matchedBy==="ref" (only "pr-number"/"text"), so the pr-number bucket was permanently 0 in the release captain's report. Own test passes.
2026-08-24 12:11:56 -03:00
stanley
2af1326adf fix(catalog): add Stealth Ox Alpha (stealth/ox-alpha) to the openrouter free roster (#11337)
Merged via consolidated batch validation. Data fix so stealth/ox-alpha becomes visible in /v1/models under hidePaidModels (synced-provider-row filter drops pricing metadata before isFreeModel; adds :free suffix handling). Own test passes.
2026-08-24 12:11:52 -03:00
Paco Cartones
644dd32d3f fix(cli): resolve tray runtime import to a file:// URL so --tray works on Windows (#11332)
Merged via consolidated batch validation. Fixes omniroute server --tray on Windows: absolute paths passed to dynamic import() are parsed as URLs, and a Windows drive letter (C:) isn't a supported URL scheme. Resolves via pathToFileURL. Own regression test passes.
2026-08-24 12:11:49 -03:00
Diego Rodrigues de Sa e Souza
9df3f8923d fix(build): stop bundling the better-sqlite3 stub at runtime (#11343) (#11391)
Merged via consolidated batch validation (worktree `.claude/worktrees/batch-0824e`, 27-PR batch). Critical fix: next.config.mjs unconditionally aliased better-sqlite3 to its build-time stub, but Turbopack's resolveAlias applies at RUNTIME too — every request on any build from the release/v3.8.50 tip answered HTTP 500 because the real driver was never loaded. Gates green; own tests pass.
2026-08-24 12:11:36 -03:00
oyi77
fa7ccaf679 fix(providers): stop silently dropping reasoning effort on opencode families (#10788)
Dispatch: OpencodeExecutor.transformRequest stripped the effort-suffixed
alias (e.g. glm-5.2-high) down to the base id and injected a flat
reasoning_effort body field — but opencode-go's ChatCompletionRequest has
no such field for non-DeepSeek families, so the tier never reached the
upstream and every request ran at default effort. Only DeepSeek V4
accepts the flat field (its native contract, #4647), so it keeps the old
rewrite; every other family now forwards the aliased model id verbatim,
which is their only native effort mechanism.

Registry: declare supportedThinkingEfforts on the base rows that had
aliases but no tier vocabulary — opencode-go (glm-5.2, mimo-v2.5,
grok-4.5, hy3, kimi-k3, qwen3.7-max/plus), the shared zen/go row
(qwen3.6-plus) and opencode-zen (deepseek-v4-pro/flash, glm-5.2,
kimi-k3) — so catalog variant synthesis (#9485) and
sanitizeReasoningEffortForProvider clamp from one source of truth.
nvidia z-ai/glm-5.2 is declared reasoning-capable with an EMPTY tier
list: its upstream only exposes a binary enable_thinking switch
(mapNvidiaGlm52ReasoningParams), so no honest tiers exist to advertise.

Ollama Cloud declarations were already landed upstream (#11307); this
change covers the remaining providers named in #10788.
2026-08-24 22:06:59 +07:00
KaspaPulse
85b2a06fad feat(dashboard): surface exclusive managed leases in Sessions view
Reuse the official exclusive-lease authority for durable idle visibility, and use pending-request accounting only for the localized active indication. Preserve legacy session fields and rows while de-duplicating leased connections and withholding lease ownership and fencing data.

Refs #10514

Follow-up to #10362
2026-08-24 13:53:27 +00:00
Markus Hartung
0b7ac870ef sync with tip before push 2026-08-24 09:55:31 -03:00
Markus Hartung
9fedc1c411 merge #11381 onto updated tip 2026-08-24 09:50:48 -03:00
Markus Hartung
e589831952 sync with tip before push 2026-08-24 09:46:03 -03:00
Diego Rodrigues de Sa e Souza
04d2a60331 fix(video): make one-frame scene sampling deterministic (#11344)
Merged via consolidated batch validation. Makes scene_aware Video Bridge sampling deterministic for a one-frame budget: falls back to the midpoint of the active full-video/focus window and reports policyEffective: uniform (a single scene candidate can't preserve both temporal ends). Adds opt-in real-FFmpeg fixture matrix (rapid edge cuts, one-frame budget, static/gradual scenes, sub-second clips, detector failure). Static gates green; own regression suite (videoBridgeSampler.test.ts, video-bridge-sampler-ffmpeg.test.ts) passed in the combined-batch run. Related to #9760. Thanks!
2026-08-24 09:44:50 -03:00
Markus Hartung
d23bfefec0 merge #11383 onto updated tip 2026-08-24 09:44:36 -03:00
Markus Hartung
c8ad44e018 merge #11350 onto updated tip 2026-08-24 09:41:55 -03:00
Diego Rodrigues de Sa e Souza
c83116e634 fix(video): isolate drill-down cache by principal (#11369)
Merged via consolidated batch validation (worktree `.claude/worktrees/batch-0824d`). Video Bridge FU-08 drill-down cache substrate hardening (explicitly PARTIAL per the PR body — no production producer/callsite feeds this cache yet): canonical isolation by principalId+sessionId+videoRef, loopback broker auth, strict Zod contracts, per-principal + global LRU quotas, full JPEG decode/re-encode with truncated-scan and polyglot-tail rejection, cancellation-safe atomic replacement. Static gates green; own regression suite (videoBridgeDrilldown.test.ts, video-bridge-drilldown-authz.test.ts, video-bridge-drilldown-route.test.ts) passed in the combined-batch run. Thanks!
2026-08-24 09:39:40 -03:00
Diego Rodrigues de Sa e Souza
7715825cb8 fix(video): harden visual frame deduplication (#11382)
Merged via consolidated batch validation (worktree `.claude/worktrees/batch-0824d`), stacked on the just-merged #11362 as documented. Moves the Video Bridge frame cap to post-dedup, bounds the perceptual candidate pool to at most 2x budget (max 16), includes the dedup policy/version in result-cache identity, adds cooperative abort checks to the comparator loop. Static gates green; own dedup/cache-version regression suite passed in the combined-batch run (grayscale-16x16-mean-cells-v2 policy, real fixtures). Thanks!
2026-08-24 09:31:00 -03:00
Diego Rodrigues de Sa e Souza
761d38f433 fix(video): harden result cache identity and coalescing (#11362)
Merged via consolidated batch validation (worktree `.claude/worktrees/batch-0824d`). Completes the Video Bridge FU-01 cache-hardening slice: fingerprints authorized video bytes + result-affecting dimensions before a persistent cache hit, strict metadata validation with corrupt-entry recompute, TTL/LRU bounds by count/entry-bytes/aggregate-bytes, coalesced protected HTTPS downloads isolated by tenant, deadline/abort-bounded model selection. Static gates green; own regression suite (tests/unit/guardrails/videoBridgeResultCache.test.ts) passed in the combined-batch run. Thanks!
2026-08-24 09:26:06 -03:00
Diego Rodrigues de Sa e Souza
c6963ca5dd fix(changelog): require verified reconciliation ledger (#11345)
Merged via consolidated batch validation (worktree `.claude/worktrees/batch-0824d`). Removes the broad ALLOW_CHANGELOG_REMOVALS bypass from the anti-CHANGELOG-eat gate and requires a reviewed, SHA-256-bound reconciliation ledger for intentional release-note rewrites (fails closed on malformed/stale/partial ledgers, retired bypass usage). Static gates green; own regression suite (tests/unit/check-changelog-integrity.test.ts, tests/unit/merge-train-plan.test.ts) passed in the combined-batch run — 15/15 CLI/ledger cases. Related to #9985. Thanks!
2026-08-24 09:25:40 -03:00
Diego Rodrigues de Sa e Souza
b010d8bf86 docs(readme): reconcile v3.8.50 metrics and contributors (#11356)
Merged via consolidated batch validation (worktree `.claude/worktrees/batch-0824d`). Reconciles README/diagram claims against the live release branch with explicit, non-conflated denominators (merged-PR ranking vs GitHub Contributors REST vs normalized Git census) and adds a repository-local SVG validator. Static gates green; own SVG-validator + render-pipeline tests (tests/unit/docs-validate-svg.test.ts) passed in the combined-batch run, docs:check-all clean per the PR's own evidence. Thanks!
2026-08-24 09:25:29 -03:00
Diego Rodrigues de Sa e Souza
fdcd15e6a9 docs(openapi): document try proxy operation (#11363)
Merged via consolidated batch validation (worktree `.claude/worktrees/batch-0824d`). Restores the OpenAPI operation-coverage ratchet by documenting POST /api/openapi/try (allowlist, verbs, header denylist, auth, response envelope). Static gates green (typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity); own contract test (tests/unit/openapi-security-tiers.test.ts) passed in the combined-batch run. Thanks!
2026-08-24 09:25:18 -03:00
Diego Rodrigues de Sa e Souza
12b8df02dd fix(catalog): keep large builds event-loop responsive (#11367)
Merged via consolidated batch validation (worktree `.claude/worktrees/batch-0824d`, 11-PR video-bridge/catalog/ops batch, tip `dafb4ae8`). Fixes the #9147 catalog-scale event-loop regression: reuses one build-local capability snapshot, yields cooperatively during catalog/virtual-pool construction, reads only persisted TTL settings. Static gates: typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity all green. Own regression test (tests/unit/9147-catalog-eventloop-yield.test.ts) reproduced the RED→GREEN transition in isolated runs per the PR's own evidence; under current shared-devbox load (10-15, multiple parallel sessions) the test intermittently reports INFRA-RED exactly as the PR body pre-disclosed (documented starvation signature, not a code defect). Thanks for the careful RED/GREEN + INFRA-RED discipline.
2026-08-24 09:24:59 -03:00
Diego Rodrigues de Sa e Souza
38d21afc2d docs(changelog): link FU-04 pull request 2026-08-24 08:40:33 -03:00
Diego Rodrigues de Sa e Souza
05e76d6e76 docs(changelog): link FU-07 pull request 2026-08-24 08:31:59 -03:00
Diego Rodrigues de Sa e Souza
93135f8e18 feat(guardrails): add focused video analysis mode 2026-08-24 07:30:28 -03:00
Diego Rodrigues de Sa e Souza
22086a73fa fix(video-bridge): validate structural segment sampling 2026-08-24 06:35:58 -03:00
Diego Rodrigues de Sa e Souza
d4ade9d1d3 fix(video): separate tenant scope from download hash 2026-08-24 05:55:00 -03:00
Diego Rodrigues de Sa e Souza
f54c93c879 fix(video): key download flights with process HMAC 2026-08-24 05:16:13 -03:00
Diego Rodrigues de Sa e Souza
e2e48fdab8 docs(changelog): link Video Bridge cache fix PR 2026-08-24 04:37:54 -03:00
Diego Rodrigues de Sa e Souza
d2cea0811a fix(video): harden result cache identity and bounds 2026-08-24 04:31:27 -03:00
Diego Rodrigues de Sa e Souza
2f18a85310 docs(changelog): link Video Bridge contact-sheet fix 2026-08-24 03:35:10 -03:00
Diego Rodrigues de Sa e Souza
38969ad16b fix(video-bridge): render timestamped contact sheets 2026-08-24 03:20:43 -03:00
Diego Rodrigues de Sa e Souza
dafb4ae808 fix(deps): keep unused pnpm peers out of production (#11342)
* fix(deps): keep unused pnpm peers out of production

* docs(changelog): link dependency policy fix to PR 11342
2026-08-24 02:26:02 -03:00
Zartharas
c89bdb21a2 chore(changelog): document web-session contract 2026-08-24 00:07:51 -05:00
Zartharas
c5e694131a style(test): format web-session contract regression 2026-08-24 00:07:33 -05:00
Erick Kinnee
338c05dc6a fix(models): expose Ollama Cloud native effort tiers (#11307)
Validated on a 17-PR combined board: models-catalog-combo-metadata + ollama-cloud-reasoning-effort-tiers-10788 within the board's 287/287, typecheck:core clean, check:open-sse-typecheck clean, vitest 405/405. Publishes Ollama Cloud's native none/low/medium/high/max effort vocabulary for reasoning-capable passthrough/tagged models with no exact registry declaration, adds none to DeepSeek V4/GLM 5.x, and preserves narrower exact-model vocabularies (GPT-OSS) via intersection. Refs #10788. Thank you @ekinnee!
2026-08-24 01:55:47 -03:00
Nguyen Thanh Dat
6945bbaaba fix(db): escape regex metacharacters in group model patterns (#11311)
Validated on a 17-PR combined board: group-model-pattern-regex-escape within the board's 287/287, typecheck:core clean. matchesModelPattern() only substituted * before compiling to RegExp — every other metacharacter kept its regex meaning, so a malformed group pattern (unbalanced parens/brackets) threw uncaught and broke EVERY request for keys in that group, not just the malformed rule (isModelAllowedForKey has no try/catch and runs on the chat completion path and the /v1/models catalog). Thank you @ntdat812!
2026-08-24 01:55:42 -03:00
Ravi Tharuma
690f684bfc feat(audio): add native ElevenLabs HTTP compatibility routes (#11312)
Validated on a 17-PR combined board: elevenlabs-native-routes + hard-session-lease-bypass-inventory (9/9) within the board's 287/287, typecheck:core clean. Native ElevenLabs compatibility routes (voices, TTS, STT) reusing the stored credential via quota-preflight, sent only as xi-api-key; client authorization headers never forwarded. Closes #10556. Thank you @RaviTharuma!
2026-08-24 01:55:36 -03:00
Ravi Tharuma
c3cd1f94c0 feat(services): expose sanitized CLIProxyAPI account health (#11314)
Validated on a 17-PR combined board: cliproxy-accounts + cliproxy-tab + cliproxy-account-health + cliproxy-resolve-spawn-args-6877 (16/16) within the board's 287/287, typecheck:core clean, env-doc-sync clean. Exposes a sanitized read-only CLIProxyAPI account health view (5s-bounded client, explicit allowlist excluding names/paths/emails/tokens/status messages) through a management-authenticated API + dashboard card. Closes #6342. Thank you @RaviTharuma!
2026-08-24 01:55:31 -03:00
Webman
c21460f22a fix(lint): drain release-green hard failures on release/v3.8.50 (#9985) (#11317)
Validated on the resolved merge against the current release tip: pack-artifact-policy + cli-mcp-call-commands + cli-resilience-commands + cli-skills-commands + model-hide-multikey-11300 39/39, typecheck:core clean, eslint clean. Resolved a pt-BR.json wording conflict against #11322 (kept the tip's wording, semantically identical). Drains the real lint-fallout from the wave that was blocking the release-green verdict — dead code + newly-enforced React-Compiler hook rules. Thank you @jonlwheat2-gif!
2026-08-24 01:54:31 -03:00
Ravi Tharuma
9b14896a6c feat(api): add Google AI Studio Gemini TTS (#11315)
Validated on a 17-PR combined board: gemini-tts + vertex-media + audio-speech-handler (41/41) within the board's 287/287, typecheck:core clean. Registers public google/gemini-*-tts speech models and translates OpenAI-compatible /v1/audio/speech to the AI Studio generateContent audio contract, reusing the Vertex inline-audio/PCM/WAV conversion path. Batch TTS only, Gemini Live is out of scope. Thank you @RaviTharuma!
2026-08-24 01:50:44 -03:00
Ravi Tharuma
29f26293c3 feat(compression): isolate sync engines in bounded worker pool (#11318)
Validated on a 17-PR combined board: compression-worker + colocate-standalone-esm-scope within the board's 287/287, typecheck:core clean, env-doc-sync clean. Offloads eligible sync compression engines into a bounded worker_threads pool with a strict serializable DTO boundary and fail-open on spawn/worker/timeout failure. Closes #11023. Thank you @RaviTharuma!
2026-08-24 01:50:39 -03:00
Nguyen Thanh Dat
cb11592441 fix(db): judge the proxy URL host by address, not by spelling (#11319)
Validated on a 17-PR combined board: upstream-proxy-host-spelling 8/8 within the board's 287/287, typecheck:core clean. Routes src/lib/db/upstreamProxy.ts through the shared outbound-guard helpers instead of a private dotted-quad regex copy that had drifted since #10843 — closes the IPv4-mapped IPv6, ULA, link-local and CGNAT bypasses while preserving the deliberate loopback allow (CLIProxyAPI on localhost:8317). Multicast widened from /224\. to the full 224.0.0.0/4, called out explicitly. Thank you @ntdat812!
2026-08-24 01:50:35 -03:00
Ravi Tharuma
5ee646e68e fix(github): verify access tokens during health checks (#11320)
Validated on a 17-PR combined board: token-health-check + token-health-no-refresh-token-expired-5326 + token-refresh-service within the board's 287/287, typecheck:core clean. GitHub access-token-only connections are now actively verified on each due health interval (via the existing Copilot token exchange); the parent credential is marked expired only on a confirmed 401, never on 403/429/5xx/network failures; response bodies and transport messages no longer enter token-refresh logs. Closes #10352. Thank you @RaviTharuma!
2026-08-24 01:50:30 -03:00
Paco Cartones
6984676d95 fix(quality): report the real failure line and stop double-counting ci.yml gates (#11321)
Validated on a 17-PR combined board: validate-release-green within the board's 287/287, typecheck:core clean. Two accuracy bugs in the release-green verdict tool: an unanchored regex blamed a passing test line (matching a filename containing 'fail'), and 6 gates were double-recorded as both hard-failure and drift due to an id-format mismatch (ci.yml script name vs curated id). Found while reading the #9985 verdict — good catch.
2026-08-24 01:50:26 -03:00
Paco Cartones
79f8ae9d1e fix(i18n): add the 3 pt-BR CLI keys that break the locale parity test (#11322)
Validated on a 17-PR combined board: typecheck:core clean, gates within baseline. Restores 3 missing pt-BR CLI keys (setup.opencode, serve.tls_cert, serve.tls_key) — parity restored, 823/823. Thank you @pacocartones!
2026-08-24 01:49:52 -03:00
Nguyen Thanh Dat
04b2c47940 fix(i18n): restore three placeholders dropped from the pt catalogue (#11325)
Validated on a 17-PR combined board: i18n-placeholder-parity within the board's 287/287, typecheck:core clean. Restores 3 dropped placeholders in pt.json (the visible one: the cache tile's subtitle was repeating its own label instead of showing the total) and adds a 42-locale placeholder-set gate so this class of drift can't recur silently. Thank you @ntdat812!
2026-08-24 01:49:48 -03:00
Paco Cartones
24ac71465e test(db): make singleton reset survive the full suite and un-skip the 3 DB-state tests (#11327)
Validated on a 17-PR combined board: capture-critical-db-state 7/7 (all three previously-skipped tests now run) within the board's 287/287, typecheck:core clean. Fixes the racy DATA_DIR-after-dynamic-import isolation and removes a duplicate type declaration. Thank you @pacocartones!
2026-08-24 01:49:42 -03:00
Nguyen Thanh Dat
8d6f91b558 fix(security): refuse proxy-authorization and proxy-authenticate upstream (#11328)
Validated on a 17-PR combined board: upstream-headers-proxy-auth within the board's 287/287, typecheck:core clean, gates within baseline. proxy-authorization and proxy-authenticate join the FORBIDDEN denylist — forwarding proxy-authorization to a model provider would hand that provider the operator's own proxy credential. Thank you @ntdat812!
2026-08-24 01:49:37 -03:00
Diego Rodrigues de Sa e Souza
c3698eedcb fix(dashboard): route the Adapta tutorial CTA through the branded shortener (#11329)
Validated on a 17-PR combined board: TSX parses clean, eslint clean. Adapta tutorial CTA href now points at the branded shortener (link.omniroute.online/adapta) while keeping the visible link text as the real domain. Completes #11196's shortener rollout.
2026-08-24 01:49:32 -03:00
Aman
9e7096a048 refactor(providers): use canonical contract imports 2026-08-23 23:36:47 -05:00
Aman
a84f0b683e test(providers): cover web-session contract publication 2026-08-23 23:36:47 -05:00
Aman
ae0b79ab7c feat(api): publish web-session credential contract 2026-08-23 23:36:47 -05:00
Aman
6daa31de0b feat(providers): add web-session contract builder 2026-08-23 23:36:46 -05:00
Diego Rodrigues de Sa e Souza
adca3b881c fix(kie): map remaining google-imagen Market ids to their real KIE upstream ids (#11326)
Merging --admin with red discrimination (merge-gates §4). Fails: ESLint warnings ratchet drift (inherited base-red), Unit Tests shards containing stream-timing.test.ts (CPU-contention timing flake, assert.ok(total >= 15)ms — unrelated to this PR's scope, open-sse/handlers/imageGeneration.ts), and dast-smoke (advisory, isRequired:null).
2026-08-24 01:10:23 -03:00
Diego Rodrigues de Sa e Souza
ac02c5b42f fix(resilience): don't clear an active rate-limit cooldown for non-quota_exhausted errors (#11277) (#11310)
Merging --admin: only fails are ESLint warnings ratchet drift (inherited base-red) and dast-smoke (advisory, isRequired:null). Zero overlap with this PR's scope (src/lib/usage/providerLimits.ts).
2026-08-23 22:55:33 -03:00
Diego Rodrigues de Sa e Souza
07d1816a45 fix(providers): hidden models leak into GET /v1/models (#11300) (#11309)
Merging --admin: only fails are ESLint warnings ratchet drift (inherited) and dast-smoke (advisory, isRequired:null). Zero overlap with this PR's file scope (src/app/api/v1/models/catalog.ts).
2026-08-23 22:35:29 -03:00
220 changed files with 6385 additions and 2044 deletions

View File

@@ -46,7 +46,7 @@ Repository map and Reference Documentation sections below.
## Project at a Glance
**OmniRoute** — unified AI proxy/router. One endpoint, 350 LLM providers, auto-fallback.
**OmniRoute** — unified AI proxy/router. One endpoint, 351 LLM providers, auto-fallback.
| Layer | Location | Purpose |
| ------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

View File

@@ -1,5 +1,5 @@
# ── Multi-stage Dockerfile for Native Bun Runtime (web-latest-bun) ───────────
FROM oven/bun:1.3.14-slim AS base
FROM oven/bun:1.4.0-slim AS base
WORKDIR /app
RUN apt-get update \
@@ -50,7 +50,7 @@ ENV NODE_ENV=production
RUN bun run --quiet build
# ── Runner Base stage (100% Bun Native Production Runtime) ──────────────────
FROM oven/bun:1.3.14-slim AS runner-base
FROM oven/bun:1.4.0-slim AS runner-base
LABEL org.opencontainers.image.title="omniroute" \
org.opencontainers.image.description="Unified AI proxy — route any LLM through one endpoint (Bun Native)" \

View File

@@ -7,7 +7,7 @@
# 🚀 OmniRoute — The Free AI Gateway
<img src="./docs/diagrams/readme-hero.svg" width="100%" alt="OmniRoute — Never stop coding. Every AI tool → 350 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 1595% tokens (~89% avg) — never hit limits. 350 AI providers · 90+ free tiers · ~1.51B free tokens/mo · 19 routing strategies · $0 to start."/>
<img src="./docs/diagrams/readme-hero.svg" width="100%" alt="OmniRoute — Never stop coding. Every AI tool → 351 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 1595% tokens (~89% avg) — never hit limits. 351 AI providers · 90+ free tiers · ~1.51B free tokens/mo · 19 routing strategies · $0 to start."/>
</div>
@@ -210,7 +210,7 @@ curl http://localhost:20128/v1/chat/completions \
</div>
<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint and 350 providers. Automatic fallback keeps routing while another healthy target is available. Six pillars: resilient fallback across 350 providers · up to 95% token savings on eligible workloads · $0 to start with 90+ free tiers and 56 recurring/keyless free-forever providers · 35 CLI/agent integrations through one config · OpenAI, Claude, Gemini and Responses API compatibility at /v1 · production controls including circuit breakers, TLS stealth, MCP 110 tools, A2A, memory, guardrails, evals and 39,000+ static test declarations across 5,100+ tracked test files."/>
<img src="./docs/diagrams/promise-pillars.svg" width="100%" alt="The Promise — One endpoint and 351 providers. Automatic fallback keeps routing while another healthy target is available. Six pillars: resilient fallback across 351 providers · up to 95% token savings on eligible workloads · $0 to start with 90+ free tiers and 56 recurring/keyless free-forever providers · 35 CLI/agent integrations through one config · OpenAI, Claude, Gemini and Responses API compatibility at /v1 · production controls including circuit breakers, TLS stealth, MCP 110 tools, A2A, memory, guardrails, evals and 39,000+ static test declarations across 5,100+ tracked test files."/>
<br/>
<br/>
@@ -461,7 +461,7 @@ All **19** strategies — mix & match per combo step:
</div>
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — a dated feature snapshot vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 350 providers, 90+ free tiers built in, 19 routing strategies, 12-engine token compression, built-in MCP server with 110 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA and 43 i18n UI locales. OmniRoute is MIT-licensed and self-hostable. Competitor capabilities and counts may change; see the linked methodology."/>
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — a dated feature snapshot vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 351 providers, 90+ free tiers built in, 19 routing strategies, 12-engine token compression, built-in MCP server with 110 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA and 43 i18n UI locales. OmniRoute is MIT-licensed and self-hostable. Competitor capabilities and counts may change; see the linked methodology."/>
<sub>📊 Full methodology &amp; per-feature detail vs 9router, OpenRouter, CLIProxyAPI &amp; LiteLLM → [`docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md`](docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md)</sub>
@@ -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 **350-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 **351-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)
<div align="center">
## 🌐 350 AI Providers — 154 Catalog-Marked Free
## 🌐 351 AI Providers — 154 Catalog-Marked Free
</div>
> **350 registered providers** across the canonical chat, media, search, local, cloud-agent and system collections, including **154 carrying `hasFree: true` discovery metadata**. The chat model registry covers **268 providers / 2,566 distinct provider-model pairs / 1,312 raw model IDs**; the separate free-budget catalog has **455 per-model rows**, **40 recurring pools** and **56 recurring/keyless free-forever providers**. These are different denominators by design; definitions and pool-deduped calculations live in the [Provider Reference](docs/reference/PROVIDER_REFERENCE.md) and [Free Tiers](docs/reference/FREE_TIERS.md).
> **351 registered providers** across the canonical chat, media, search, local, cloud-agent and system collections, including **154 carrying `hasFree: true` discovery metadata**. The chat model registry covers **268 providers / 2,566 distinct provider-model pairs / 1,312 raw model IDs**; the separate free-budget catalog has **455 per-model rows**, **40 recurring pools** and **56 recurring/keyless free-forever providers**. These are different denominators by design; definitions and pool-deduped calculations live in the [Provider Reference](docs/reference/PROVIDER_REFERENCE.md) and [Free Tiers](docs/reference/FREE_TIERS.md).
<div align="center">

View File

@@ -0,0 +1 @@
- **feat(providers):** publish a management-authenticated versioned web-session credential contract from OmniRoute's canonical browser credential metadata ([#11340](https://github.com/diegosouzapw/OmniRoute/pull/11340)) — thanks @Zartharas

View File

@@ -0,0 +1 @@
- **feat(search):** Add Xquik X search with typed results, credential validation, REST routing, and MCP selection ([#11370](https://github.com/diegosouzapw/OmniRoute/pull/11370)) — thanks @kriptoburak

View File

@@ -0,0 +1 @@
- **feat(dashboard):** surface durable exclusive managed leases in the existing Sessions view, keeping leased clients visible across idle gaps while marking connections with in-flight work as active ([#11389](https://github.com/diegosouzapw/OmniRoute/pull/11389)) — thanks @KaspaPulse

View File

@@ -0,0 +1 @@
- **fix(free-models):** the shared `isFreeModel()` predicate no longer reports catalog entries marked `freeType: "discontinued"` as free, so `hidePaidModels` can't route to Pollinations' seven premium models that now require a paid key ([#11441](https://github.com/diegosouzapw/OmniRoute/pull/11441))

View File

@@ -0,0 +1 @@
- **fix(electron):** the packaged Windows desktop build now passes the #7592 cold-restart smoke end to end. Five defects were found and fixed on the way: (1) optional-pack staging failed on any machine whose `tar` is GNU tar — it reads the drive letter in an absolute `-f C:\...` archive path as a remote rsh host (`Cannot connect to C:`), so staging now passes a bare filename with `cwd` at the tarball directory and surfaces tar stderr on failure; (2) the Electron `files` allowlist was missing `lib/loginHeaderCapture.js`, so the packaged main process crashed at startup with `Cannot find module './lib/loginHeaderCapture'`; (3) electron-builder ≥26 injects an `!**/node_modules/**` ignore into every extraResources pattern list that no positive filter can override, which silently dropped the staged runtime `node_modules` (including the better-sqlite3 N-API prebuild) from `resources/app` — a fresh v3.8.50 desktop build would have shipped with no native SQLite driver and reproduced the #7592 sql.js fallback on every machine; an `afterPack` hook now restores the staged `node_modules` after packing; (4) the packaged-app smoke harness redirected `USERPROFILE` into its temp DATA_DIR, but Electron resolves the Roaming profile from `%USERPROFILE%\AppData\Roaming\<name>` (USERPROFILE takes precedence over the APPDATA env var) and the path service throws instead of creating it, so `requestSingleInstanceLock()` returned false and the app exited(0) silently before `app.whenReady()` — the harness now pre-creates the derived tree, and `ensureSmokeEnvDirs` is exported and unit-tested; (5) the #7592 driver assertion parsed a `[DB] Driver: ...` line that the server's primary DB path never printed (only the unused `openDatabaseAsync()` did) — `getDbInstance()` now emits the same line on open so the guard can actually assert the native driver. Also: the smoke env-allowlist unit test hardcoded POSIX paths and could only pass on Linux/macOS; expectations are now host-agnostic, with new regression tests for the USERPROFILE-derived tree and `tarPack` under absolute Windows-style paths

View File

@@ -0,0 +1 @@
- **fix(memory):** Embedding Model Quick select, Embedding Source remote dropdown, and Rerank selector now list every configured provider with embedding/rerank support instead of only chat-catalog text matches plus OpenRouter live discovery; a generic OpenAI-compatible `/embeddings` + Cohere-compatible `/rerank` runtime fallback resolves any configured chat provider's embedding/rerank endpoint, so unlisted providers no longer fail with "Unknown embedding provider"; both memory selectors gained a free-text model override

View File

@@ -12,6 +12,7 @@
"@dnd-kit/core",
"@dnd-kit/sortable",
"@dnd-kit/utilities",
"@eslint/compat",
"@huggingface/transformers",
"@lobehub/icons",
"@modelcontextprotocol/sdk",
@@ -60,6 +61,7 @@
"eslint",
"eslint-config-next",
"eslint-plugin-sonarjs",
"espree",
"express",
"fast-check",
"fetch-socks",

View File

@@ -2372,16 +2372,6 @@
"count": 2
}
},
"src/lib/guardrails/videoBridgeContactSheet.ts": {
"@typescript-eslint/no-unused-vars": {
"count": 1
}
},
"src/lib/guardrails/videoBridgeRuntime.ts": {
"@typescript-eslint/no-unused-vars": {
"count": 1
}
},
"src/lib/guardrails/visionBridgeHelpers.ts": {
"@typescript-eslint/no-unused-vars": {
"count": 1
@@ -2422,11 +2412,6 @@
"count": 1
}
},
"src/lib/memory/embedding/index.ts": {
"no-restricted-imports": {
"count": 1
}
},
"src/lib/memory/genericBackend.ts": {
"@typescript-eslint/no-unused-vars": {
"count": 1

View File

@@ -0,0 +1 @@
feat(resilience): atomically enforce cumulative global, provider, and account concurrency limits

View File

@@ -0,0 +1,98 @@
# Design: Pluggable External Durable-State DB Backend (PostgreSQL / MySQL)
Status: PROPOSAL · Discussion issue: [#8075](https://github.com/diegosouzapw/OmniRoute/issues/8075) · Author: @oyi77
Grounded in the tree at `release/v3.8.51` (`3192eb88d`). Every number below was measured on that tree, not estimated.
---
## 0. Why this document exists
#8075 asks five questions (backends & order, abstraction contract, what stays SQLite-only, config surface, migration path). This document answers them with a census of how deeply the current data layer is coupled to SQLite, and proposes a repository-contract seam that lets external backends be adopted per domain instead of via a big-bang driver swap.
## 1. Measured coupling census (`release/v3.8.51`)
| Surface | Count | Implication for external backends |
|---|---|---|
| `src/lib/db/*.ts` modules calling `.prepare()` / `.transaction()` | **126 files** | The synchronous SQLite call shape is the de-facto data API; every module is a translation candidate |
| `.pragma()` call sites | **36** | No equivalent in PG/MySQL — each needs an audit (many are performance tuning that becomes server config) |
| SQLite migrations on disk | **159** | A second dialect needs its own migration lineage, not a translator |
| `sqlite-vec` / `vec0` referencing files | **9** | Vector search must move to an external store (Qdrant proposed in #8075) |
| FTS5 referencing files | **8** | Maps to Postgres `tsvector` / MySQL `FULLTEXT` — dialect work |
| Existing driver adapters | **4** (`better-sqlite3`, `node:sqlite`, `bun:sqlite`, `sql.js`) behind `SqliteAdapter` (`src/lib/db/adapters/types.ts`) | Proves a seam exists at the DRIVER level — but all four are SQLite; the seam OmniRoute actually needs is one level up |
The decisive fact: **the adapter interface is synchronous** (`prepare().run/get/all`, sync closure transactions). PostgreSQL and MySQL drivers are inherently async. A faithful external backend behind `SqliteAdapter` is therefore impossible without faking sync over async — which is exactly the trap #8037/#8073 already flagged ("not a drop-in ORM/driver swap"). The contract must live ABOVE the adapter layer.
## 2. Proposed contract: durable-state repositories, not a driver swap
Introduce a `DurableStateStore` port with per-domain repositories, defined once and implemented per dialect:
```ts
// src/lib/db/ports/ — dialect-agnostic, async, transactional by unit-of-work
interface UnitOfWork {
connections: ConnectionRepository; // provider connections + credentials
apiKeys: ApiKeyRepository; // keys, groups, usage-limit fields
combos: ComboRepository; // combo defs + routing policies
quotaState: QuotaStateRepository; // quota/account state, cooldowns
sessionAffinity: AffinityRepository; // sticky routing state
audit: AuditRepository; // config audit log
}
interface DurableStateStore {
readonly driver: "sqlite" | "postgres" | "mysql";
withUnitOfWork<T>(fn: (uow: UnitOfWork) => Promise<T>): Promise<T>;
healthCheck(): Promise<{ ok: boolean; latencyMs: number }>;
}
```
Deliberate exclusions from v1 (stay SQLite-local, matching #8075 §3): WAL/VACUUM/PRAGMA lifecycle, file backup/import/export, `sqlite-vec` vector storage (external backends delegate vectors to Qdrant), FTS (dialect-native fulltext later).
### What makes each repository shippable
The single-writer pattern OmniRoute already uses internally (targeted raw-SQL stat bumps like `touchConnectionLastUsed`, single-writer caches) maps cleanly onto `UnitOfWork`. Repositories are adopted **per domain**: a deployment can run `postgres` for connections+keys while hot-path ephemeral state stays local — because the port is injected at the repository boundary, not under 126 modules.
## 3. Sequencing: PostgreSQL first, MySQL second
1. **Postgres-first** (`pg` + `pg-pool`): richer native JSONB (several modules persist JSON blobs), `tsvector`, `INSERT ... ON CONFLICT` semantics closest to `INSERT OR REPLACE` usage.
2. **MySQL 8+ after**, gated by a shared **dialect-conformance suite**: the same behavioral test pack runs against both implementations (schema bootstrap, UoW rollback, credential round-trip incl. encryption-at-rest fields, pagination/ordering contracts). A backend is "supported" only when the suite is green.
Rationale: one conformance suite prevents the MySQL implementation from drifting into a shim that passes smoke tests but corrupts ordering/collation edge cases.
## 4. Config surface
```
DATABASE_DRIVER=sqlite # sqlite (default) | postgres | mysql
DATABASE_URL=postgres://... # required when driver != sqlite
DATABASE_POOL_MAX=10
DATABASE_TLS_REJECT_UNAUTHORIZED=1
DATABASE_MIGRATIONS_TABLE=_omniroute_migrations
```
- Default stays `sqlite` — zero-config npm/Electron/Termux behavior is non-negotiable (#8075 §6).
- Health check surfaces in the existing `/api/monitoring/health` payload next to `inflightRequests`.
- Migrations: per-dialect lineage directories (`migrations-postgres/`, `migrations-mysql/`) with their own runner sharing the safety checks (mass-migration abort, pre-migration backup → pg_dump/mysqldump equivalent) already proven in `migrationRunner.ts`.
## 5. Migration path (one-way export tool)
`omniroute db export --to postgres --dsn ...`:
1. Snapshot `storage.sqlite` (reuse `createPreMigrationBackup`).
2. Replay schema from the target dialect's lineage to head.
3. Copy tables row-by-row through the new repositories (not raw SQL translation), preserving IDs; re-encrypt nothing (credential ciphertexts are dialect-neutral strings today).
4. Verify with row-count + checksum comparison per table; write a receipt file.
5. Refuse to continue on any mismatch (fail-closed).
## 6. Phased delivery plan
| Phase | Deliverable | Risk gate |
|---|---|---|
| P1 | `ports/` contract + SQLite implementation of `ConnectionRepository` + conformance-suite skeleton running against SQLite itself | Suite green on the reference driver |
| P2 | Postgres implementation of the same repo + suite green on PG | Suite green on PG |
| P3 | Remaining domains (apiKeys, combos, quotaState, affinity, audit) on PG | Full-suite parity vs SQLite run |
| P4 | MySQL via conformance suite | Suite green on MySQL |
| P5 | Export tool + docs | Round-trip receipt on a 1GB-scale fixture |
P1P2 alone deliver value: a clustered deployment can share connection/key state while everything else stays local.
## 7. Explicitly out of scope
- Translating the remaining ~120 SQLite-shaped modules verbatim ("just make prepare() hit Postgres") — rejected: it fakes sync over async and preserves dialect bugs forever.
- Replacing `sqlite-vec` with pgvector — #8075 names Qdrant; keeping vector search out-of-process also keeps the lean proxy core lean (4.0 modular direction).

View File

@@ -1,4 +1,4 @@
<svg viewBox="0 0 1200 350" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Animated terminal demoing the OmniRoute CLI: omniroute providers list (350 providers registered, anthropic, codex, glm, kimi shown active), omniroute combo list (always-on priority, cost-saver, fusion-panel, context-relay) and omniroute health (healthy, 18412 requests in 24h, p95 412ms, circuit breakers 24 closed, 1 half-open, 0 open), cycling over 85 top-level commands: providers, oauth, keys, combo, nodes, models, cache, compression, cost, usage, quota, health, resilience, telemetry, logs, audit, mcp, a2a, cloud, memory, skills, eval, doctor, repl, tunnel, backup, sync, webhooks, policy, pricing, translator, simulate and more.">
<svg viewBox="0 0 1200 350" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Animated terminal demoing the OmniRoute CLI: omniroute providers list (351 providers registered, anthropic, codex, glm, kimi shown active), omniroute combo list (always-on priority, cost-saver, fusion-panel, context-relay) and omniroute health (healthy, 18412 requests in 24h, p95 412ms, circuit breakers 24 closed, 1 half-open, 0 open), cycling over 85 top-level commands: providers, oauth, keys, combo, nodes, models, cache, compression, cost, usage, quota, health, resilience, telemetry, logs, audit, mcp, a2a, cloud, memory, skills, eval, doctor, repl, tunnel, backup, sync, webhooks, policy, pricing, translator, simulate and more.">
<desc>Compact animated terminal cycling three real OmniRoute CLI commands with a typewriter effect and a scrolling subcommand ticker; the first frame shows the completed providers-list screen.</desc>
<defs><clipPath id="tickerClip"><rect x="12" y="304" width="1176" height="40"/></clipPath><clipPath id="tw0"><rect x="64" y="46" height="26" width="0"><animate attributeName="width" calcMode="discrete" values="0;31;61;92;122;153;184;214;245;245" keyTimes="0;0.012;0.018;0.024;0.030;0.036;0.042;0.048;0.054;1" dur="18s" repeatCount="indefinite"/></rect></clipPath><clipPath id="tw1"><rect x="64" y="46" height="26" width="0"><animate attributeName="width" calcMode="discrete" values="0;26;51;76;102;128;153;178;204;204" keyTimes="0;0.348;0.351;0.357;0.363;0.369;0.375;0.381;0.387;1" dur="18s" repeatCount="indefinite"/></rect></clipPath><clipPath id="tw2"><rect x="64" y="46" height="26" width="0"><animate attributeName="width" calcMode="discrete" values="0;20;41;61;82;102;122;143;163;163" keyTimes="0;0.678;0.684;0.690;0.696;0.702;0.708;0.714;0.720;1" dur="18s" repeatCount="indefinite"/></rect></clipPath></defs>
<rect width="1200" height="350" fill="#0d1117"/>
@@ -6,7 +6,7 @@
<path d="M 0 34 L 1200 34" stroke="#ffffff" stroke-opacity="0.08" stroke-width="1"/>
<circle cx="24" cy="17" r="6" fill="#ff5f56"/><circle cx="46" cy="17" r="6" fill="#ffbd2e"/><circle cx="68" cy="17" r="6" fill="#27c93f"/>
<text x="600" y="22" text-anchor="middle" font-family="Consolas, 'Courier New', monospace" font-size="13" fill="#71717a">omniroute &#8212; 85 top-level commands</text>
<g font-family="Consolas, 'Courier New', monospace" font-size="17"><animate attributeName="opacity" values="1;0;0" keyTimes="0;0.006;1" dur="18s" repeatCount="indefinite"/><text x="64" y="66" fill="#F7F6FC">omniroute providers list</text><text x="40" y="100" font-weight="700" fill="#38bdf8">OmniRoute Providers</text><text x="40" y="128" fill="#a1a1aa">1f3a9c2e&#160;&#160;anthropic&#160;&#160;&#160;Claude Max 20x&#160;&#160;&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="154" fill="#a1a1aa">8c2d5b1a&#160;&#160;codex&#160;&#160;&#160;&#160;&#160;&#160;&#160;Codex Pro (team)&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="180" fill="#a1a1aa">f4e0a97b&#160;&#160;glm&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;GLM Coding Plan&#160;&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="206" fill="#a1a1aa">03bd6e5f&#160;&#160;kimi&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Kimi K2 free&#160;&#160;&#160;&#160;&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="232" fill="#71717a">&#8230; 346 more providers</text></g><g opacity="1" font-family="Consolas, 'Courier New', monospace" font-size="17">
<g font-family="Consolas, 'Courier New', monospace" font-size="17"><animate attributeName="opacity" values="1;0;0" keyTimes="0;0.006;1" dur="18s" repeatCount="indefinite"/><text x="64" y="66" fill="#F7F6FC">omniroute providers list</text><text x="40" y="100" font-weight="700" fill="#38bdf8">OmniRoute Providers</text><text x="40" y="128" fill="#a1a1aa">1f3a9c2e&#160;&#160;anthropic&#160;&#160;&#160;Claude Max 20x&#160;&#160;&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="154" fill="#a1a1aa">8c2d5b1a&#160;&#160;codex&#160;&#160;&#160;&#160;&#160;&#160;&#160;Codex Pro (team)&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="180" fill="#a1a1aa">f4e0a97b&#160;&#160;glm&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;GLM Coding Plan&#160;&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="206" fill="#a1a1aa">03bd6e5f&#160;&#160;kimi&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Kimi K2 free&#160;&#160;&#160;&#160;&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="232" fill="#71717a">&#8230; 347 more providers</text></g><g opacity="1" font-family="Consolas, 'Courier New', monospace" font-size="17">
<animate attributeName="opacity" values="1;1;0;0" keyTimes="0;0.315;0.33;1" dur="18s" repeatCount="indefinite"/>
<text x="40" y="66" fill="#22c55e">$</text>
<g clip-path="url(#tw0)"><text x="64" y="66" fill="#F7F6FC">omniroute providers list</text></g>
@@ -14,7 +14,7 @@
<animate attributeName="x" calcMode="discrete" values="64;95;125;156;186;217;248;278;309;309" keyTimes="0.000;0.012;0.018;0.024;0.030;0.036;0.042;0.048;0.054;1" dur="18s" repeatCount="indefinite"/>
<animate attributeName="opacity" values="0;0;1;0.2;1;0.2;1;0;0" keyTimes="0;0.011;0.012;0.022;0.032;0.042;0.052;0.074;1" dur="18s" repeatCount="indefinite"/>
</rect>
<text x="40" y="100" font-weight="700" fill="#38bdf8" opacity="0"><animate attributeName="opacity" calcMode="discrete" values="0;0;1" keyTimes="0;0.045;0.047" dur="18s" repeatCount="indefinite"/>OmniRoute Providers</text><text x="40" y="128" fill="#a1a1aa" opacity="0"><animate attributeName="opacity" calcMode="discrete" values="0;0;1" keyTimes="0;0.053;0.055" dur="18s" repeatCount="indefinite"/>1f3a9c2e&#160;&#160;anthropic&#160;&#160;&#160;Claude Max 20x&#160;&#160;&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="154" fill="#a1a1aa" opacity="0"><animate attributeName="opacity" calcMode="discrete" values="0;0;1" keyTimes="0;0.061;0.063" dur="18s" repeatCount="indefinite"/>8c2d5b1a&#160;&#160;codex&#160;&#160;&#160;&#160;&#160;&#160;&#160;Codex Pro (team)&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="180" fill="#a1a1aa" opacity="0"><animate attributeName="opacity" calcMode="discrete" values="0;0;1" keyTimes="0;0.069;0.07100000000000001" dur="18s" repeatCount="indefinite"/>f4e0a97b&#160;&#160;glm&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;GLM Coding Plan&#160;&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="206" fill="#a1a1aa" opacity="0"><animate attributeName="opacity" calcMode="discrete" values="0;0;1" keyTimes="0;0.077;0.079" dur="18s" repeatCount="indefinite"/>03bd6e5f&#160;&#160;kimi&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Kimi K2 free&#160;&#160;&#160;&#160;&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="232" fill="#71717a" opacity="0"><animate attributeName="opacity" calcMode="discrete" values="0;0;1" keyTimes="0;0.085;0.08700000000000001" dur="18s" repeatCount="indefinite"/>&#8230; 346 more providers</text>
<text x="40" y="100" font-weight="700" fill="#38bdf8" opacity="0"><animate attributeName="opacity" calcMode="discrete" values="0;0;1" keyTimes="0;0.045;0.047" dur="18s" repeatCount="indefinite"/>OmniRoute Providers</text><text x="40" y="128" fill="#a1a1aa" opacity="0"><animate attributeName="opacity" calcMode="discrete" values="0;0;1" keyTimes="0;0.053;0.055" dur="18s" repeatCount="indefinite"/>1f3a9c2e&#160;&#160;anthropic&#160;&#160;&#160;Claude Max 20x&#160;&#160;&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="154" fill="#a1a1aa" opacity="0"><animate attributeName="opacity" calcMode="discrete" values="0;0;1" keyTimes="0;0.061;0.063" dur="18s" repeatCount="indefinite"/>8c2d5b1a&#160;&#160;codex&#160;&#160;&#160;&#160;&#160;&#160;&#160;Codex Pro (team)&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="180" fill="#a1a1aa" opacity="0"><animate attributeName="opacity" calcMode="discrete" values="0;0;1" keyTimes="0;0.069;0.07100000000000001" dur="18s" repeatCount="indefinite"/>f4e0a97b&#160;&#160;glm&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;GLM Coding Plan&#160;&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="206" fill="#a1a1aa" opacity="0"><animate attributeName="opacity" calcMode="discrete" values="0;0;1" keyTimes="0;0.077;0.079" dur="18s" repeatCount="indefinite"/>03bd6e5f&#160;&#160;kimi&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Kimi K2 free&#160;&#160;&#160;&#160;&#160;&#160;<tspan fill='#22c55e'>active</tspan></text><text x="40" y="232" fill="#71717a" opacity="0"><animate attributeName="opacity" calcMode="discrete" values="0;0;1" keyTimes="0;0.085;0.08700000000000001" dur="18s" repeatCount="indefinite"/>&#8230; 347 more providers</text>
</g><g opacity="0" font-family="Consolas, 'Courier New', monospace" font-size="17">
<animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.333;0.34800000000000003;0.648;0.663;1" dur="18s" repeatCount="indefinite"/>
<text x="40" y="66" fill="#22c55e">$</text>

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,4 +1,4 @@
<svg viewBox="0 0 1200 780" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Comparison table: OmniRoute versus 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute is the only one with the full set: 350 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, a built-in MCP server with 110 tools, A2A protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, desktop/Termux/PWA, 43 UI locales and 100% MIT self-hosted. 9router has free providers, RTK compression and translation but no MCP, A2A, memory, guardrails, cloud agents or stealth. OpenRouter is a hosted SaaS with 400+ models, guardrails and a hosted MCP but is not self-hosted and lacks A2A, memory, cloud agents and stealth. CLIProxyAPI is a light OAuth proxy with two routing strategies. LiteLLM has 100+ providers, A2A and extensive guardrails but no memory, compression, free tier, stealth or cloud agents.">
<svg viewBox="0 0 1200 780" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Comparison table: OmniRoute versus 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute is the only one with the full set: 351 providers, 90+ free providers built-in, 19 routing strategies, 12-engine token compression, a built-in MCP server with 110 tools, A2A protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, desktop/Termux/PWA, 43 UI locales and 100% MIT self-hosted. 9router has free providers, RTK compression and translation but no MCP, A2A, memory, guardrails, cloud agents or stealth. OpenRouter is a hosted SaaS with 400+ models, guardrails and a hosted MCP but is not self-hosted and lacks A2A, memory, cloud agents and stealth. CLIProxyAPI is a light OAuth proxy with two routing strategies. LiteLLM has 100+ providers, A2A and extensive guardrails but no memory, compression, free tier, stealth or cloud agents.">
<desc>Static-header comparison table where each capability row fades in top to bottom; the OmniRoute column is highlighted and shows a check or a leading value in every row, while competitors show a mix of checks, partials and crosses.</desc>
<defs>
<pattern id="gC" width="32" height="32" patternUnits="userSpaceOnUse"><path d="M 32 0 L 0 0 0 32" fill="none" stroke="#ffffff" stroke-opacity="0.05" stroke-width="1"/></pattern>

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,4 +1,4 @@
<svg viewBox="0 0 1200 540" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The OmniRoute promise: one endpoint and 350 providers. Six pillars. Resilient fallback: automatic routing continues while another healthy target is available. Save up to 95 percent of eligible tokens: RTK plus Caveman stacked compression averages about 89 percent on tool-heavy sessions. Zero dollars to start: 90+ providers with a free tier and 56 recurring or keyless free-forever providers. Every tool works: 35 CLI and agent integration records, including Claude Code, Codex, Cursor, Cline, Copilot and Antigravity, through one config. One endpoint: OpenAI, Claude, Gemini and Responses API translation at /v1. Production controls: circuit breakers, TLS stealth, MCP with 110 tools, A2A, memory, guardrails, evals, and 39,000+ static test declarations across 5,100+ tracked test files.">
<svg viewBox="0 0 1200 540" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The OmniRoute promise: one endpoint and 351 providers. Six pillars. Resilient fallback: automatic routing continues while another healthy target is available. Save up to 95 percent of eligible tokens: RTK plus Caveman stacked compression averages about 89 percent on tool-heavy sessions. Zero dollars to start: 90+ providers with a free tier and 56 recurring or keyless free-forever providers. Every tool works: 35 CLI and agent integration records, including Claude Code, Codex, Cursor, Cline, Copilot and Antigravity, through one config. One endpoint: OpenAI, Claude, Gemini and Responses API translation at /v1. Production controls: circuit breakers, TLS stealth, MCP with 110 tools, A2A, memory, guardrails, evals, and 39,000+ static test declarations across 5,100+ tracked test files.">
<desc>Animated promise card: six pillar tiles fade in in reading order, then a soft colored border highlight sweeps from tile to tile in a continuous cycle.</desc>
<defs>
<pattern id="gridPaperP" width="32" height="32" patternUnits="userSpaceOnUse">
@@ -21,7 +21,7 @@
<line x1="150" y1="53" x2="1160" y2="53" stroke="#232b38" stroke-width="1.5"/>
</g>
<g>
<text x="40" y="100" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="23" font-weight="600" fill="#c9d1d9">One endpoint. <tspan fill="#a78bfa" font-weight="800">350 providers.</tspan> Never stop building — OmniRoute picks <tspan fill="#7ee787" font-weight="700">the cheapest one that works</tspan>.</text>
<text x="40" y="100" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="23" font-weight="600" fill="#c9d1d9">One endpoint. <tspan fill="#a78bfa" font-weight="800">351 providers.</tspan> Never stop building — OmniRoute picks <tspan fill="#7ee787" font-weight="700">the cheapest one that works</tspan>.</text>
</g>
<g font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif">
@@ -38,7 +38,7 @@
<line x1="3.9" y1="3.9" x2="18.1" y2="18.1"/>
</g>
<text x="102" y="170" font-size="18" font-weight="800" fill="#74b9ff">Never hit limits</text>
<text x="66" y="204" font-size="13.5" fill="#a1a1aa">Auto-fallback across 350 providers in</text>
<text x="66" y="204" font-size="13.5" fill="#a1a1aa">Auto-fallback across 351 providers in</text>
<text x="66" y="226" font-size="13.5" fill="#a1a1aa">milliseconds. Quota out? The next provider</text>
<text x="66" y="248" font-size="13.5" fill="#a1a1aa">takes over while a healthy target remains.</text>
</g>

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -1,4 +1,4 @@
<svg viewBox="0 0 1200 548" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="OmniRoute hero: Never stop coding. Every AI tool to 350 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot and Antigravity into free Claude, GPT and Gemini with auto-fallback. RTK + Caveman stacked compression saves 15 to 95 percent of tokens — about 89 percent average on tool-heavy sessions — so you never hit limits. Stats: 350 AI providers, 90+ free tiers, about 1.51B free tokens per month, 15 to 95 percent token savings, 19 routing strategies, zero dollars to start.">
<svg viewBox="0 0 1200 548" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="OmniRoute hero: Never stop coding. Every AI tool to 351 providers — 90+ free — through one endpoint. Claude Code, Codex, Cursor, Cline, Copilot and Antigravity into free Claude, GPT and Gemini with auto-fallback. RTK + Caveman stacked compression saves 15 to 95 percent of tokens — about 89 percent average on tool-heavy sessions — so you never hit limits. Stats: 351 AI providers, 90+ free tiers, about 1.51B free tokens per month, 15 to 95 percent token savings, 19 routing strategies, zero dollars to start.">
<desc>Animated hero card: a pulse travels the divider line and a compression bar demo repeatedly shrinks a prompt by up to 95 percent; all headline content is static and readable on the first frame.</desc>
<defs>
<pattern id="gridPaperH" width="32" height="32" patternUnits="userSpaceOnUse">
@@ -28,7 +28,7 @@
<text x="48" y="138" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="60" font-weight="800" fill="#e9edf3">Never stop coding<tspan fill="#a855f7">.</tspan></text>
<!-- subheadline -->
<text x="48" y="184" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="25" font-weight="600" fill="#c9d1d9">Every AI tool → <tspan fill="#a78bfa" font-weight="800">350 providers</tspan><tspan fill="#7ee787" font-weight="800">90+ free</tspan> — through one endpoint.</text>
<text x="48" y="184" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="25" font-weight="600" fill="#c9d1d9">Every AI tool → <tspan fill="#a78bfa" font-weight="800">351 providers</tspan><tspan fill="#7ee787" font-weight="800">90+ free</tspan> — through one endpoint.</text>
<!-- plug line -->
<text x="48" y="222" font-family="Inter, 'Segoe UI', Arial, Helvetica, system-ui, sans-serif" font-size="16.5" fill="#a1a1aa">Claude Code · Codex · Cursor · Cline · Copilot · Antigravity&#160;&#160;&#160;&#160;<tspan fill="#7ee787" font-weight="700">FREE</tspan> Claude / GPT / Gemini · auto-fallback</text>

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -66,22 +66,22 @@ Cursor, Cline, and compatible MCP client setup.
## Essential Tools (13) — Phase 1
| Tool | Scopes | Description |
| :------------------------------ | :-------------------- | :------------------------------------------------------------ |
| `omniroute_get_health` | `read:health` | Uptime, memory, circuit breakers, rate limits, cache stats |
| `omniroute_list_combos` | `read:combos` | All configured combos with strategies (optional metrics) |
| `omniroute_get_combo_metrics` | `read:combos` | Performance metrics for a specific combo |
| `omniroute_switch_combo` | `write:combos` | Activate or deactivate a combo |
| `omniroute_create_combo` | `write:combos` | Create a validated combo through the existing combo API |
| `omniroute_check_quota` | `read:quota` | Quota used/total, percent remaining, reset time, token health |
| `omniroute_route_request` | `execute:completions` | Send a chat completion through OmniRoute routing |
| `omniroute_cost_report` | `read:usage` | Cost report by period (session/day/week/month) |
| `omniroute_list_models_catalog` | `read:models` | Full model catalog with capabilities, status, pricing |
| `omniroute_radar_catalog` | `read:radar` | Local signed Radar catalog; optional provider/family filters |
| `omniroute_tool_search` | `read:tools` | Discover tools from the registered MCP catalog |
| `omniroute_web_search` | `execute:search` | Web search through the configured search providers. Not X/Twitter. |
| `omniroute_x_search` | `execute:search` | Search X (Twitter) through SuperGrok / xAI server-side `x_search`. Requires `xai-oauth` or an xAI API key. Not the X Developer Platform MCP. |
| `omniroute_web_fetch` | `execute:search` | Fetch web content through the configured fetch providers |
| Tool | Scopes | Description |
| :------------------------------ | :-------------------- | :----------------------------------------------------------------------------------------------------------------------------- |
| `omniroute_get_health` | `read:health` | Uptime, memory, circuit breakers, rate limits, cache stats |
| `omniroute_list_combos` | `read:combos` | All configured combos with strategies (optional metrics) |
| `omniroute_get_combo_metrics` | `read:combos` | Performance metrics for a specific combo |
| `omniroute_switch_combo` | `write:combos` | Activate or deactivate a combo |
| `omniroute_create_combo` | `write:combos` | Create a validated combo through the existing combo API |
| `omniroute_check_quota` | `read:quota` | Quota used/total, percent remaining, reset time, token health |
| `omniroute_route_request` | `execute:completions` | Send a chat completion through OmniRoute routing |
| `omniroute_cost_report` | `read:usage` | Cost report by period (session/day/week/month) |
| `omniroute_list_models_catalog` | `read:models` | Full model catalog with capabilities, status, pricing |
| `omniroute_radar_catalog` | `read:radar` | Local signed Radar catalog; optional provider/family filters |
| `omniroute_tool_search` | `read:tools` | Discover tools from the registered MCP catalog |
| `omniroute_web_search` | `execute:search` | Web search through the configured search providers. Not X/Twitter. |
| `omniroute_x_search` | `execute:search` | Search X through xAI/SuperGrok, or choose `xquik-search` for Xquik API results. Requires credentials for the selected backend. |
| `omniroute_web_fetch` | `execute:search` | Fetch web content through the configured fetch providers |
## Advanced Tools (11) — Phase 2

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -4,7 +4,7 @@
---
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -281,7 +281,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -43,6 +43,8 @@ tags:
description: Content moderation
- name: Rerank
description: Document reranking
- name: Search
description: Unified web, news, and X search
- name: Models
description: Available model listing
- name: Providers
@@ -1153,6 +1155,199 @@ paths:
$ref: "#/components/responses/Unauthorized"
# ─── Proxy Endpoints ──────────────────────────────────────────
/api/v1/search:
get:
tags: [Search]
summary: List search providers
description: Lists configured search providers and their supported search types.
responses:
"200":
description: Search provider catalog
content:
application/json:
schema:
type: object
required: [object, data]
properties:
object:
type: string
const: list
data:
type: array
items:
type: object
required: [id, object, created, name, search_types]
properties:
id:
type: string
object:
type: string
const: search_provider
created:
type: integer
name:
type: string
search_types:
type: array
items:
type: string
enum: [web, news, x]
post:
tags: [Search]
summary: Run a unified search
description: >-
Searches the web, news, or X through a configured provider. Set `provider`
to `xquik-search` to use Xquik for X search. The aliases `xquik` and
`xquik_search` resolve to the same provider.
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [query]
properties:
query:
type: string
minLength: 1
maxLength: 500
provider:
type: string
minLength: 1
description: A search provider id or registered alias.
examples: [xquik-search]
max_results:
type: integer
minimum: 1
maximum: 100
default: 5
search_type:
type: string
enum: [web, news, x]
default: web
offset:
type: integer
minimum: 0
default: 0
country:
type: string
maxLength: 2
language:
type: string
minLength: 2
maxLength: 5
time_range:
type: string
enum: [any, hour, day, week, month, year]
content:
type: object
properties:
snippet: { type: boolean, default: true }
full_page: { type: boolean, default: false }
format: { type: string, enum: [text, markdown], default: text }
max_characters: { type: integer, minimum: 100, maximum: 100000 }
filters:
type: object
properties:
include_domains:
type: array
maxItems: 20
items: { type: string, maxLength: 253 }
exclude_domains:
type: array
maxItems: 20
items: { type: string, maxLength: 253 }
safe_search: { type: string, enum: [off, moderate, strict] }
provider_options:
type: object
additionalProperties: true
strict_filters:
type: boolean
default: false
additionalProperties: true
responses:
"200":
description: Normalized search results
content:
application/json:
schema:
type: object
required: [id, provider, query, results, answer, usage, metrics, errors, cached]
properties:
id:
type: string
pattern: ^search-
provider:
type: string
query:
type: string
cached:
type: boolean
results:
type: array
items:
type: object
required: [title, url, snippet, position, citation]
properties:
title: { type: string }
url: { type: string, format: uri }
display_url: { type: string }
snippet: { type: string }
position: { type: integer, minimum: 1 }
score:
type: [number, "null"]
minimum: 0
maximum: 1
published_at: { type: [string, "null"] }
favicon_url: { type: [string, "null"], format: uri }
citation:
type: object
required: [provider, retrieved_at, rank]
properties:
provider: { type: string }
retrieved_at: { type: string, format: date-time }
rank: { type: integer, minimum: 1 }
answer:
type: [object, "null"]
usage:
type: object
required: [queries_used, search_cost_usd]
properties:
queries_used: { type: integer, minimum: 0 }
search_cost_usd: { type: number, minimum: 0 }
llm_tokens: { type: integer, minimum: 0 }
metrics:
type: object
required: [response_time_ms, upstream_latency_ms, total_results_available]
properties:
response_time_ms: { type: number, minimum: 0 }
upstream_latency_ms: { type: number, minimum: 0 }
gateway_latency_ms: { type: number, minimum: 0 }
total_results_available: { type: [integer, "null"], minimum: 0 }
errors:
type: array
items:
type: object
required: [provider, code, message]
properties:
provider: { type: string }
code: { type: string }
message: { type: string }
"400":
description: Invalid request, provider, credentials, or search type
"401":
$ref: "#/components/responses/Unauthorized"
"403":
description: Search provider blocked by API key or security policy
"429":
description: Every eligible provider credential is rate limited
"500":
$ref: "#/components/responses/InternalError"
"502":
description: Search provider failed
/api/v1/chat/completions:
post:
tags: [Chat]

View File

@@ -0,0 +1,23 @@
# #7778 hierarchical admission cleanup plan
1. Lock the existing single-key semaphore contract and the new atomic multi-key
contract with focused tests: no partial reservations, FIFO queueing, abort,
timeout, queue-full, idempotent release, stats, and cleanup.
2. Generalize the existing account semaphore in place. Keep `acquire()` as a
compatibility wrapper around `acquireMany()`; do not add a second scheduler
or a dependency.
3. Replace the account-only acquisition in `chatCore` with one cumulative
global/provider/account acquisition immediately before `withRateLimit`.
Reacquire the whole set whenever account rotation changes the connection,
and retain the release through streaming completion.
4. Extend the existing resilience settings pipeline (types, defaults,
normalization, schema, API response, UI, and translations) with the global
and provider caps. Relabel the old Bottleneck concurrency control as
connection/quota-scope concurrency so its real scope is explicit.
5. Run focused tests, lint, typecheck, static checks, and the full test suite;
document the behavioral change in the changelog.
Behavior intentionally preserved: zero/null concurrency bypasses a gate,
account-only callers keep using `acquire()`, blocked-account controls retain
their key format and API, and provider rate-limit queue behavior remains
unchanged.

View File

@@ -1,16 +1,16 @@
---
title: "Provider Reference"
version: 3.8.50
lastUpdated: 2026-08-23
lastUpdated: 2026-08-24
---
# 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-23
> **Last generated:** 2026-08-24
Total providers: **350**. See category breakdown below.
Total providers: **351**. See category breakdown below.
## Categories
@@ -377,7 +377,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
| `vllm` | `vllm` | vLLM | Local, self-hosted | [link](https://github.com/vllm-project/vllm) | API key optional. Configure the local vLLM OpenAI-compatible base URL (default: http://localhost:8000/v1). |
| `xinference` | `xinference` | XInference | Local, self-hosted | [link](https://inference.readthedocs.io) | API key optional. Configure the local XInference OpenAI-compatible base URL (default: http://localhost:9997/v1). |
## Search Providers (14)
## Search Providers (15)
| ID | Alias | Name | Tags | Website | Notes |
|----|-------|------|------|---------|-------|
@@ -394,6 +394,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
| `serper-search` | `serper-search` | Serper Search | Search | [link](https://serper.dev) | API key from serper.dev dashboard |
| `tavily-search` | `tavily-search` | Tavily Search | Search | [link](https://tavily.com) | API key from app.tavily.com (format: tvly-...) |
| `x-search` | `x_search` | X Search (Grok) | Search | [link](https://docs.x.ai/developers/tools/x-search) | SuperGrok OAuth (xai-oauth) or xAI API key. This is Grok X Search, not the X Developer MCP. |
| `xquik-search` | `xquik` | Xquik X Search | Search | [link](https://docs.xquik.com) | Xquik API key (xq_...). Search is metered per returned post; the catalog estimate uses 5 results. |
| `youcom-search` | `youcom-search` | You.com Search | Search | [link](https://you.com/business/api/) | X-API-Key from the You.com platform dashboard |
## Audio-only Providers (12)
@@ -438,7 +439,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
- Catalog: [`src/shared/constants/providers.ts`](../../src/shared/constants/providers.ts)
- Registry (per-model details): [`open-sse/config/providerRegistry.ts`](../../open-sse/config/providerRegistry.ts)
- Executors: [`open-sse/executors/`](../../open-sse/executors/) (108 implementations)
- Executors: [`open-sse/executors/`](../../open-sse/executors/) (109 implementations)
- Translators: [`open-sse/translator/`](../../open-sse/translator/)
## See Also

View File

@@ -45,6 +45,7 @@
"copyright": "Copyright © 2025 OmniRoute",
"buildDependenciesFromSource": false,
"npmRebuild": false,
"afterPack": "../scripts/build/afterpack-copy-node-modules.mjs",
"directories": {
"output": "dist-electron",
"buildResources": "assets"
@@ -58,6 +59,7 @@
"main.js",
"preload.js",
"loginManager.js",
"lib/loginHeaderCapture.js",
"processTree.js",
"sqlite-inspection.js",
"remoteServerPromptPreload.js",

View File

@@ -1,4 +1,6 @@
import { fixupConfigRules } from "@eslint/compat";
import nextVitals from "eslint-config-next/core-web-vitals";
import * as espree from "espree";
import tseslint from "typescript-eslint";
// #7879: bar NEW local `toNumber` definitions outside the canonical helper.
@@ -37,7 +39,22 @@ const IMPORT_BOUNDARY_RESTRICTIONS = {
/** @type {import("eslint").Linter.Config[]} */
const eslintConfig = [
...nextVitals,
...fixupConfigRules(nextVitals),
// eslint-config-next's Babel parser has not adopted ESLint 10's ScopeManager
// finalize contract yet. Plain JS/JSX does not need that parser, so use the
// ESLint-native parser while retaining Next's plugins and rules.
{
files: ["**/*.{js,jsx,mjs,cjs}"],
languageOptions: {
parser: espree,
},
},
{
files: ["**/*.{mts,cts}"],
languageOptions: {
parser: tseslint.parser,
},
},
// Pacote 4 (plano mestre testes+CI, 2026-07-04) — zero-warning policy: TODA regra roda
// como "error" e a dívida pré-existente vive congelada por arquivo+regra em
// config/quality/eslint-suppressions.json (ESLint bulk suppressions nativo). Violação
@@ -133,28 +150,45 @@ const eslintConfig = [
"no-restricted-syntax": "off",
},
},
// Relaxed rules for open-sse and tests (incremental adoption)
// Relaxed rules for TypeScript in open-sse and tests (incremental adoption).
// eslint-config-next already registers @typescript-eslint for every TS file;
// registering a second plugin object is rejected by ESLint 10.
{
files: ["open-sse/**/*.ts", "tests/**/*.mjs", "tests/**/*.ts"],
plugins: {
"@typescript-eslint": tseslint.plugin,
},
files: ["open-sse/**/*.ts", "tests/**/*.ts"],
rules: {
"@typescript-eslint/no-explicit-any": "error",
"@next/next/no-assign-module-variable": "off",
"react-hooks/rules-of-hooks": "off",
},
},
{
files: ["tests/**/*.mjs"],
plugins: {
"@typescript-eslint": tseslint.plugin,
},
rules: {
"@next/next/no-assign-module-variable": "off",
"react-hooks/rules-of-hooks": "off",
},
},
// JS/JSX files do not match eslint-config-next's TypeScript block. Register
// the plugin only for that disjoint scope so the shared unused-vars ratchet
// works without redefining the plugin for TS/TSX under ESLint 10.
{
files: ["src/**/*.{js,jsx}"],
plugins: {
"@typescript-eslint": tseslint.plugin,
},
},
// Ratchet: bar NEW unused vars/args/catches outside the `_` escape hatch.
// Pre-existing violations are frozen via config/quality/eslint-suppressions.json
// (same pattern as #7879 toNumber); only genuinely NEW unused bindings fail
// lint. `args: "all"` (not `after-used`) so a leading unused param is never
// silently skipped, e.g. `function handle(req, _opts, next)` must flag `req`.
// eslint-config-next already registers @typescript-eslint; registering it again
// in this block is rejected by ESLint 10.
{
files: ["src/**/*.{ts,tsx,js,jsx}", "open-sse/**/*.ts", "tests/**/*.{ts,tsx,mjs}"],
plugins: {
"@typescript-eslint": tseslint.plugin,
},
rules: {
"@typescript-eslint/no-unused-vars": [
"error",

View File

@@ -1,6 +1,6 @@
# OmniRoute
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 350 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
> OmniRoute is a free, open-source AI Gateway that acts as a universal API proxy for multi-provider LLMs. It provides smart routing, automatic fallback, load balancing, and format translation across 351 AI providers — all through a single OpenAI-compatible endpoint. Includes a built-in MCP Server (110 tools), A2A v0.3 protocol, Memory/Skills systems, Cloud Agents (codex, cursor, devin, jules), Guardrails framework, and an Electron desktop app.
## Overview
@@ -277,7 +277,7 @@ OmniRoute solves the problem of managing multiple AI provider subscriptions, quo
## Key Features (v3.8.50)
### Core Proxy
- **350 AI providers** with automatic format translation
- **351 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
- **350-provider catalog** with 90+ free tiers, one-click account imports, and bulk key add
- **351-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 110 tools / 33 scopes** (canonical + memory/skill/agentSkill/githubSkill/pool/notion/obsidian/localCorpus/gamification/plugin modules)

View File

@@ -408,6 +408,7 @@ export const EMBEDDING_PROVIDERS: Record<string, EmbeddingProvider> = {
},
],
},
};
const EMBEDDING_PROVIDER_ALIASES: Record<string, string> = {
@@ -470,6 +471,38 @@ export function getEmbeddingProvider(providerId: string): EmbeddingProvider | nu
return EMBEDDING_PROVIDERS[resolveEmbeddingProviderId(providerId)] || null;
}
/**
* Derive an OpenAI-compatible embeddings config for a chat provider that has NO
* curated EMBEDDING_PROVIDERS entry. Works for any registry provider whose base
* URL ends in /chat/completions by swapping that suffix for /embeddings (groq,
* mistral, together, upstage, fireworks, nvidia, vercel-ai-gateway, ...).
* Dynamic-URL providers (no usable static base) derive to
* null — they need bespoke URL handling, not a bogus endpoint.
*
* This is a FALLBACK only: callers must check getEmbeddingProvider() first so
* curated entries keep their specialized configuration.
*/
export function deriveEmbeddingProviderForChatProvider(
providerId: string,
chatEntry: { id?: string; baseUrl?: string | string[] } | null | undefined
): EmbeddingProvider | null {
if (!chatEntry) return null;
const rawBase = Array.isArray(chatEntry.baseUrl)
? chatEntry.baseUrl[0]
: chatEntry.baseUrl;
if (!rawBase || typeof rawBase !== "string") return null;
// stripTrailingSlashes-equivalent without importing open-sse utils here:
const base = rawBase.replace(/\/+$/, "");
if (!base.endsWith("/chat/completions")) return null;
return {
id: providerId,
baseUrl: `${base.slice(0, -"/chat/completions".length)}/embeddings`,
authType: "apikey",
authHeader: "bearer",
models: [],
};
}
/**
* Parse embedding model string (format: "provider/model" or just "model")
* Returns { provider, model }
@@ -485,6 +518,18 @@ export function parseEmbeddingModel(
const slashIdx = modelStr.indexOf("/");
if (slashIdx > 0) {
const rawProvider = modelStr.slice(0, slashIdx);
// A configured provider_node whose prefix exactly equals the requested
// provider segment always wins — even when that segment is also an alias
// of a curated provider (a local node must not be hijacked by a registry
// alias). Same exact-match precedence documented for
// EMBEDDING_MODEL_ALIASES above.
const dynamicExact =
dynamicProviders && dynamicProviders.find((dp) => dp.id === rawProvider);
if (dynamicExact) {
return { provider: rawProvider, model: modelStr.slice(slashIdx + 1) };
}
const resolvedProvider = resolveEmbeddingProviderId(rawProvider);
if (EMBEDDING_PROVIDERS[resolvedProvider]) {

View File

@@ -69,6 +69,31 @@ export interface FreeModelTotals {
const RECURRING = new Set<FreeModelFreeType>(["recurring-daily", "recurring-monthly", "keyless"]);
/**
* What each free-tier regime engages for "can I route here without paying?".
* Exhaustive by construction: adding a member to `FreeModelFreeType` will not
* compile until it is classified here. `discontinued` is the one regime a
* provider uses to retire a free tier behind a paid key — it does NOT grant
* free access, and the shared predicate (`isFreeModel`) must read this instead
* of treating every catalogued id as free. `RECURRING` (above) answers a
* different question (which regimes feed the headline token totals) and is left
* independent on purpose — deriving it from this table would silently change
* the homepage totals.
*/
const FREE_REGIME_TRAITS = {
"recurring-daily": { grantsFreeAccess: true },
"recurring-monthly": { grantsFreeAccess: true },
"recurring-credit": { grantsFreeAccess: true },
"recurring-uncapped": { grantsFreeAccess: true },
"one-time-initial": { grantsFreeAccess: true },
keyless: { grantsFreeAccess: true },
discontinued: { grantsFreeAccess: false },
} satisfies Record<FreeModelFreeType, { grantsFreeAccess: boolean }>;
export function grantsFreeAccess(freeType: FreeModelFreeType): boolean {
return FREE_REGIME_TRAITS[freeType].grantsFreeAccess;
}
/**
* Deposit-unlock boosts: a one-time small top-up that permanently raises a
* provider's recurring free quota. Kept OUT of the steady headline and surfaced

View File

@@ -12,5 +12,15 @@
export const OPENCODE_ZEN_GO_SHARED_MODELS = Object.freeze([
{ id: "kimi-k2.7-code", name: "Kimi K2.7 Code" },
{ id: "qwen3.5-plus", name: "Qwen3.5 Plus", targetFormat: "claude", supportsVision: false },
{ id: "qwen3.6-plus", name: "Qwen3.6 Plus", targetFormat: "claude", supportsVision: false },
{
id: "qwen3.6-plus",
name: "Qwen3.6 Plus",
targetFormat: "claude",
supportsVision: false,
// #10788: effort-tier aliases exist as explicit registry rows; declare the
// vocabulary on the shared base row so variant synthesis and the sanitizer
// agree on it for both opencode-go and opencode-zen.
supportsReasoning: true,
supportedThinkingEfforts: ["high", "max"],
},
]);

View File

@@ -18,7 +18,17 @@ export const nvidiaProvider: RegistryEntry = {
passthroughModels: true,
models: [
// #6108: z-ai/glm-5.1 EOL'd 2026-07-02 (direct probe returns 410) — dropped.
{ id: "z-ai/glm-5.2", name: "GLM 5.2" },
// #10788: NVIDIA's hosted GLM-5.2 exposes a BINARY thinking switch
// (chat_template_kwargs.enable_thinking), not effort tiers — see
// mapNvidiaGlm52ReasoningParams. Declaring an empty tier list keeps the
// catalog from synthesizing unresolvable -low/-high/-max variant ids while
// still marking the model reasoning-capable.
{
id: "z-ai/glm-5.2",
name: "GLM 5.2",
supportsReasoning: true,
supportedThinkingEfforts: [],
},
// #3329/#6108: minimaxai/minimax-m3 stays excluded from the nvidia tier — it
// still 404s here for most callers; the single 200 probe in #6108 was not
// reproducible enough to override the #3329 guard. Re-add only once NVIDIA

View File

@@ -19,9 +19,15 @@ export const opencode_goProvider: RegistryEntry = {
// `kimi-k2.7-code` (the live API rejects the plain `kimi-k2.7` alias for
// `/chat/completions`, even though the docs config example uses it).
// GLM-5.2 — base model + effort-tier aliases (#6922).
// OpencodeExecutor rewrites the alias to the canonical id and injects
// reasoning_effort, mirroring the deepseek-v4-pro-* pattern.
{ id: "glm-5.2", name: "GLM-5.2", supportsReasoning: true },
// #10788: the tier vocabulary is declared on the base row so the catalog's
// variant synthesis (#9485) and the effort sanitizer share one source of
// truth with OpencodeExecutor's EFFORT_TIERS.
{
id: "glm-5.2",
name: "GLM-5.2",
supportsReasoning: true,
supportedThinkingEfforts: ["high", "max"],
},
{ id: "glm-5.2-high", name: "GLM-5.2 (high effort)", supportsReasoning: true },
{ id: "glm-5.2-max", name: "GLM-5.2 (max effort)", supportsReasoning: true },
@@ -34,11 +40,16 @@ export const opencode_goProvider: RegistryEntry = {
{ id: "kimi-k2.6", name: "Kimi K2.6" },
{ id: "kimi-k2.5", name: "Kimi K2.5" },
// #8353: Kimi K3 base + max-effort alias from the OpenCode Go registry.
{ id: "kimi-k3", name: "Kimi K3", supportsReasoning: true },
{ id: "kimi-k3", name: "Kimi K3", supportsReasoning: true, supportedThinkingEfforts: ["max"] },
{ id: "kimi-k3-max", name: "Kimi K3 (max effort)", supportsReasoning: true },
// MiMo-V2.5 — base model + effort-tier aliases (#6922).
{ id: "mimo-v2.5-pro", name: "MiMo-V2.5-Pro", supportsReasoning: true },
{ id: "mimo-v2.5", name: "MiMo-V2.5", supportsReasoning: true },
{
id: "mimo-v2.5",
name: "MiMo-V2.5",
supportsReasoning: true,
supportedThinkingEfforts: ["high", "max"],
},
{ id: "mimo-v2.5-high", name: "MiMo-V2.5 (high effort)", supportsReasoning: true },
{ id: "mimo-v2.5-max", name: "MiMo-V2.5 (max effort)", supportsReasoning: true },
// #3110: MiniMax M3 via OpenCode Go tier
@@ -59,7 +70,14 @@ export const opencode_goProvider: RegistryEntry = {
// so combo routing skips them when the request contains image blocks,
// preventing image content from reaching a vision-incapable upstream.
// #8353: effort-tier aliases from the OpenCode Go registry.
{ id: "qwen3.7-max", name: "Qwen3.7 Max", targetFormat: "claude", supportsVision: false },
{
id: "qwen3.7-max",
name: "Qwen3.7 Max",
targetFormat: "claude",
supportsVision: false,
supportsReasoning: true,
supportedThinkingEfforts: ["high", "max"],
},
{
id: "qwen3.7-max-high",
name: "Qwen3.7 Max (high effort)",
@@ -79,6 +97,8 @@ export const opencode_goProvider: RegistryEntry = {
name: "Qwen3.7 Plus",
targetFormat: "claude",
supportsVision: false,
supportsReasoning: true,
supportedThinkingEfforts: ["high", "max"],
},
{
id: "qwen3.7-plus-high",
@@ -111,7 +131,13 @@ export const opencode_goProvider: RegistryEntry = {
supportsReasoning: true,
},
// #8353: hy3 is the Go-tier base id (distinct from hy3-preview / hy3-free).
{ id: "hy3", name: "Hunyuan3", contextLength: 256000, supportsReasoning: true },
{
id: "hy3",
name: "Hunyuan3",
contextLength: 256000,
supportsReasoning: true,
supportedThinkingEfforts: ["none", "low", "high"],
},
{
id: "hy3-none",
name: "Hunyuan3 (none effort)",
@@ -201,7 +227,12 @@ export const opencode_goProvider: RegistryEntry = {
targetFormat: "openai-responses",
},
// #8353: Grok 4.5 + effort tiers from the OpenCode Go registry.
{ id: "grok-4.5", name: "Grok 4.5", supportsReasoning: true },
{
id: "grok-4.5",
name: "Grok 4.5",
supportsReasoning: true,
supportedThinkingEfforts: ["low", "medium", "high"],
},
{ id: "grok-4.5-low", name: "Grok 4.5 (low effort)", supportsReasoning: true },
{ id: "grok-4.5-medium", name: "Grok 4.5 (medium effort)", supportsReasoning: true },
{ id: "grok-4.5-high", name: "Grok 4.5 (high effort)", supportsReasoning: true },

View File

@@ -79,18 +79,35 @@ export const opencode_zenProvider: RegistryEntry = {
},
// ── DeepSeek ────────────────────────────────────────────────
{ id: "deepseek-v4-pro", name: "DeepSeek V4 Pro" },
{ id: "deepseek-v4-flash", name: "DeepSeek V4 Flash" },
// #10788: same tier vocabulary as opencode-go's DeepSeek rows — the Zen
// upstream accepts the identical effort set on these models.
{
id: "deepseek-v4-pro",
name: "DeepSeek V4 Pro",
supportsReasoning: true,
supportedThinkingEfforts: ["none", "low", "high", "max"],
},
{
id: "deepseek-v4-flash",
name: "DeepSeek V4 Flash",
supportsReasoning: true,
supportedThinkingEfforts: ["none", "low", "high", "max"],
},
// ── GLM / Z.AI ─────────────────────────────────────────────
{ id: "glm-5.2", name: "GLM-5.2" },
{
id: "glm-5.2",
name: "GLM-5.2",
supportsReasoning: true,
supportedThinkingEfforts: ["high", "max"],
},
// ── MiniMax ────────────────────────────────────────────────
// #3110: MiniMax M3 — frontier coding model with 1M context
{ id: "minimax-m3", name: "MiniMax M3", contextLength: 1048576, supportsVision: true },
// ── Kimi / Moonshot ────────────────────────────────────────
{ id: "kimi-k3", name: "Kimi K3" },
{ id: "kimi-k3", name: "Kimi K3", supportsReasoning: true, supportedThinkingEfforts: ["max"] },
// kimi-k2.7-code declared identically on opencode-go — see OPENCODE_ZEN_GO_SHARED_MODELS.
// ── Qwen ───────────────────────────────────────────────────

View File

@@ -218,3 +218,29 @@ export function getAllRerankModels() {
}
return models;
}
/**
* Derive a Cohere-compatible rerank config for a chat provider that has NO
* curated RERANK_PROVIDERS entry. Works for any registry provider whose base
* URL ends in /chat/completions by swapping that suffix for /rerank (groq,
* mistral, vercel-ai-gateway, ...). Dynamic-URL providers (no usable static
* base, e.g. dynamic account-scoped hosts) derive to null — they need bespoke
* URL handling.
*
* This is a FALLBACK only: callers must check getRerankProvider() first so
* curated entries keep their specialized configuration and format adapters.
*/
export function deriveRerankProviderForChatProvider(providerId, chatEntry) {
if (!chatEntry) return null;
const rawBase = Array.isArray(chatEntry.baseUrl) ? chatEntry.baseUrl[0] : chatEntry.baseUrl;
if (!rawBase || typeof rawBase !== "string") return null;
const base = rawBase.replace(/\/+$/, "");
if (!base.endsWith("/chat/completions")) return null;
return {
id: providerId,
baseUrl: `${base.slice(0, -"/chat/completions".length)}/rerank`,
authType: "apikey",
authHeader: "bearer",
models: [],
};
}

View File

@@ -330,6 +330,25 @@ export const SEARCH_PROVIDERS: Record<string, SearchProviderConfig> = {
timeoutMs: 60_000,
cacheTTLMs: 5 * 60 * 1000,
},
// Direct X API search through Xquik. Keep it fallback-only so the existing
// SuperGrok provider remains the default for search_type "x".
"xquik-search": {
id: "xquik-search",
name: "Xquik X Search",
baseUrl: "https://xquik.com/api/v1/x/tweets/search",
method: "GET",
authType: "apikey",
authHeader: "x-api-key",
costPerQuery: 0.00075,
freeMonthlyQuota: 0,
searchTypes: ["x"],
defaultMaxResults: 5,
maxMaxResults: 20,
timeoutMs: 15_000,
cacheTTLMs: 5 * 60 * 1000,
fallbackOnly: true,
},
};
/**
@@ -377,6 +396,8 @@ export const SEARCH_PROVIDER_ALIASES: Record<string, string> = {
c7: "context7",
x_search: "x-search",
x: "x-search",
xquik: "xquik-search",
xquik_search: "xquik-search",
};
export function resolveSearchProviderId(providerId: string): string {

View File

@@ -1,246 +1,218 @@
import { SEARCH_PROVIDERS } from "../config/searchRegistry.ts";
import { registerExecutor, getRegisteredExecutor, hasRegisteredExecutor } from "./registry.ts";
import {
registerLazyExecutor,
loadRegisteredExecutor,
hasRegisteredExecutor,
} from "./registry.ts";
// Type-only: pulls no runtime code, keeps DefaultExecutor the only eager class.
import type { BaseExecutor } from "./base.ts";
import { AntigravityExecutor } from "./antigravity.ts";
import { GithubExecutor } from "./github.ts";
import { GheCopilotExecutor } from "./ghe-copilot.ts";
import { QoderExecutor } from "./qoder.ts";
import { KiroExecutor } from "./kiro.ts";
import { CodexExecutor } from "./codex.ts";
import { CodexAppServerExecutor } from "./codex-app-server.ts";
import { CursorExecutor } from "./cursor.ts";
import { TraeExecutor } from "./trae.ts";
import { DefaultExecutor } from "./default.ts";
import { BedrockExecutor } from "./bedrock.ts";
import { GlmExecutor } from "./glm.ts";
import { PollinationsExecutor } from "./pollinations.ts";
import { CloudflareAIExecutor } from "./cloudflare-ai.ts";
import { FreebuffExecutor } from "./freebuff.ts";
import { OpencodeExecutor } from "./opencode.ts";
import { VertexExecutor } from "./vertex.ts";
import { CliproxyapiExecutor } from "./cliproxyapi.ts";
import { DarioExecutor } from "./dario.ts";
import { NineRouterExecutor } from "./ninerouter.ts";
import { PerplexityWebExecutor } from "./perplexity-web.ts";
import { GrokWebExecutor } from "./grok-web.ts";
import { GeminiWebExecutor } from "./gemini-web.ts";
import { TencentAIStudioWebExecutor } from "./tencent-aistudio-web.ts";
import { GeminiBusinessExecutor } from "./gemini-business.ts";
import { ChatGptWebExecutor } from "./chatgpt-web.ts";
import { ChatGptWebCodexExecutor } from "./chatgpt-web-codex.ts";
import { BlackboxWebExecutor } from "./blackbox-web.ts";
import { MuseSparkWebExecutor } from "./muse-spark-web.ts";
import { AzureOpenAIExecutor } from "./azure-openai.ts";
import { AzureAiExecutor } from "./azure-ai.ts";
import { CommandCodeExecutor } from "./commandCode.ts";
import { GitlabExecutor } from "./gitlab.ts";
import { NlpCloudExecutor } from "./nlpcloud.ts";
import { DevinDesktopExecutor } from "./devin-desktop.ts";
import { ZedHostedExecutor } from "./zed-hosted.ts";
import { DevinCliExecutor } from "./devin-cli.ts";
import { ZcodeExecutor } from "./zcode.ts";
import { DevinCliAgenticExecutor } from "./devin-cli-agentic.ts";
import { AuggieExecutor } from "./auggie.ts";
import { DeepSeekWebExecutor } from "./deepseek-web.ts";
import { DeepSeekWebWithAutoRefreshExecutor } from "./deepseek-web-with-auto-refresh.ts";
import { AdaptaWebExecutor } from "./adapta-web.ts";
import { CopilotWebExecutor } from "./copilot-web.ts";
import { CopilotM365WebExecutor } from "./copilot-m365-web.ts";
import { MicrosoftDesignerWebExecutor } from "./microsoft-designer-web.ts";
import { AdobeFireflyExecutor } from "./adobe-firefly.ts";
import { VeoAIFreeWebExecutor } from "./veoaifree-web.ts";
import { DuckDuckGoWebExecutor } from "./duckduckgo-web.ts";
import { FeloWebExecutor } from "./felo-web.ts";
import { T3ChatWebExecutor } from "./t3-chat-web.ts";
import { ClaudeWebExecutor } from "./claude-web.ts";
import { InnerAiExecutor } from "./inner-ai.ts";
import { HuggingChatExecutor } from "./huggingchat.ts";
import { YuanbaoWebExecutor } from "./yuanbao-web.ts";
import { PoeWebExecutor } from "./poe-web.ts";
import { VeniceWebExecutor } from "./venice-web.ts";
import { NotionWebExecutor } from "./notion-web.ts";
import { V0VercelWebExecutor } from "./v0-vercel-web.ts";
import { CheaperInferenceExecutor } from "./cheaperinference.ts";
import { KimiWebExecutor } from "./kimi-web.ts";
import { DoubaoWebExecutor } from "./doubao-web.ts";
import { QwenWebExecutor } from "./qwen-web.ts";
import { RaycastExecutor } from "./raycast.ts";
import { HailuoWebExecutor } from "./hailuo-web.ts";
import { ZaiWebExecutor } from "./zai-web.ts";
import { KimiExecutor } from "./kimi.ts";
import { MoonshotExecutor } from "./moonshot.ts";
import { TheOldLlmExecutor } from "./theoldllm.ts";
import { ChipotleExecutor } from "./chipotle.ts";
import { LMArenaExecutor } from "./lmarena.ts";
import { GrokCliExecutor } from "./grok-cli.ts";
import { CodeBuddyCnExecutor } from "./codebuddy-cn.ts";
import { ZenmuxFreeExecutor } from "./zenmux-free.ts";
import { CloudflarePlaygroundExecutor } from "./cloudflare-playground.ts";
import { TinyCmsExecutor } from "./tinycms.ts";
import { HyperAgentExecutor } from "./hyperagent.ts";
import { XaiExecutor } from "./xai.ts";
import { PromptQlExecutor } from "./promptql.ts";
import { ConolWebExecutor } from "./conol-web.ts";
// R0.3 — declarative built-in table. The object literal stays as the single
// place built-ins are declared (compile-time duplicate-key safety; the
// check:known-symbols gate parses this literal from source), but lookup goes
// through the ExecutorRegistry (./registry.ts): every entry is registered at
// module load below, and getExecutor()/hasSpecializedExecutor() consult the
// registry — the literal is never read at request time.
const executors = {
antigravity: new AntigravityExecutor(),
agy: new AntigravityExecutor(),
github: new GithubExecutor(),
"ghe-copilot": new GheCopilotExecutor(),
qoder: new QoderExecutor(),
kiro: new KiroExecutor(),
"amazon-q": new KiroExecutor("amazon-q"),
bedrock: new BedrockExecutor(),
codex: new CodexExecutor(),
"codex-app-server": new CodexAppServerExecutor({}, "codex-app-server"),
"chatgpt-web-codex": new ChatGptWebCodexExecutor(),
"cgpt-codex": new ChatGptWebCodexExecutor(),
cursor: new CursorExecutor(),
trae: new TraeExecutor(),
glm: new GlmExecutor("glm"),
"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(),
cmd: new CommandCodeExecutor(), // Alias
gitlab: new GitlabExecutor(),
"gitlab-duo": new GitlabExecutor("gitlab-duo"),
nlpcloud: new NlpCloudExecutor(),
pollinations: new PollinationsExecutor(),
pol: new PollinationsExecutor(), // Alias
"cloudflare-ai": new CloudflareAIExecutor(),
cf: new CloudflareAIExecutor(), // Alias
freebuff: new FreebuffExecutor(),
fb: new FreebuffExecutor(), // Alias
"opencode-zen": new OpencodeExecutor("opencode-zen"),
"opencode-go": new OpencodeExecutor("opencode-go"),
opencode: new OpencodeExecutor("opencode-zen"), // Alias for opencode-zen
vertex: new VertexExecutor(),
"vertex-partner": new VertexExecutor(),
cliproxyapi: new CliproxyapiExecutor(),
cpa: new CliproxyapiExecutor(), // Alias
dario: new DarioExecutor(),
dr: new DarioExecutor(), // Alias
"9router": new NineRouterExecutor(),
nr: new NineRouterExecutor(), // Alias
"perplexity-web": new PerplexityWebExecutor(),
"pplx-web": new PerplexityWebExecutor(), // Alias
"grok-web": new GrokWebExecutor(),
"claude-web": new ClaudeWebExecutor(),
"cw-web": new ClaudeWebExecutor(), // Alias
"gemini-web": new GeminiWebExecutor(),
gweb: new GeminiWebExecutor(), // Alias
"gemini-business": new GeminiBusinessExecutor(),
gembiz: new GeminiBusinessExecutor(), // Alias
"chatgpt-web": new ChatGptWebExecutor(),
"cgpt-web": new ChatGptWebExecutor(), // Alias
"blackbox-web": new BlackboxWebExecutor(),
"bb-web": new BlackboxWebExecutor(), // Alias
"muse-spark-web": new MuseSparkWebExecutor(),
"ms-web": new MuseSparkWebExecutor(), // Alias
"devin-desktop": new DevinDesktopExecutor(),
"zed-hosted": new ZedHostedExecutor(),
"devin-cli": new DevinCliExecutor(),
zcode: new ZcodeExecutor(),
zc: new ZcodeExecutor(), // Alias
"devin-cli-agentic": new DevinCliAgenticExecutor(),
devin: new DevinCliExecutor(), // Alias
"deepseek-web": new DeepSeekWebWithAutoRefreshExecutor(),
"ds-web": new DeepSeekWebWithAutoRefreshExecutor(), // Alias
"adapta-web": new AdaptaWebExecutor(),
"adp-web": new AdaptaWebExecutor(), // Alias
"copilot-web": new CopilotWebExecutor(),
"copilot-m365-web": new CopilotM365WebExecutor(),
copilot: new CopilotWebExecutor(), // Alias
"microsoft-designer-web": new MicrosoftDesignerWebExecutor(),
msdesigner: new MicrosoftDesignerWebExecutor(), // Alias
"adobe-firefly": new AdobeFireflyExecutor(),
firefly: new AdobeFireflyExecutor(), // Alias
"veoaifree-web": new VeoAIFreeWebExecutor(),
"veo-free": new VeoAIFreeWebExecutor(), // Alias
"duckduckgo-web": new DuckDuckGoWebExecutor(),
ddgw: new DuckDuckGoWebExecutor(), // Alias
"felo-web": new FeloWebExecutor(),
felo: new FeloWebExecutor(), // Alias
"t3-web": new T3ChatWebExecutor(),
t3chat: new T3ChatWebExecutor(), // Alias
"inner-ai": new InnerAiExecutor(),
"in-ai": new InnerAiExecutor(), // Alias
huggingchat: new HuggingChatExecutor(),
hc: new HuggingChatExecutor(), // Alias
"yuanbao-web": new YuanbaoWebExecutor(),
"tencent-aistudio-web": new TencentAIStudioWebExecutor(),
tasw: new TencentAIStudioWebExecutor(),
ybw: new YuanbaoWebExecutor(), // Alias
"poe-web": new PoeWebExecutor(),
// R0.3 — declarative built-in table, made LAZY by #11220.
//
// The object literal below stays as the single place built-ins are declared
// (compile-time duplicate-key safety; the check:known-symbols gate parses this
// literal from source), but its values are now deferred loaders instead of
// eagerly-constructed instances. At module load every ALIAS is registered in
// declaration order; the class import + construction happen on first use via
// loadRegisteredExecutor() and are cached in the same registry a static
// registration would have populated.
//
// Why: importing this barrel previously pulled all ~100 executor modules and
// constructed every instance at boot — ~0.71.2s and ~35MB of heap measured on
// top of the minimal set — even for deployments that use a handful of
// providers. Bundlers split the dynamic imports into on-demand chunks.
//
// Contract preserved (pinned by tests/unit/executor-map-golden.test.ts):
// - keys and their ORDER are byte-stable
// - each alias still gets its OWN instance (aliases never share)
// - ctor arguments are unchanged
const lazyExecutors: Record<string, () => Promise<BaseExecutor>> = {
antigravity: () => import("./antigravity.ts").then((m) => new m.AntigravityExecutor()),
agy: () => import("./antigravity.ts").then((m) => new m.AntigravityExecutor()),
github: () => import("./github.ts").then((m) => new m.GithubExecutor()),
"ghe-copilot": () => import("./ghe-copilot.ts").then((m) => new m.GheCopilotExecutor()),
qoder: () => import("./qoder.ts").then((m) => new m.QoderExecutor()),
kiro: () => import("./kiro.ts").then((m) => new m.KiroExecutor()),
"amazon-q": () => import("./kiro.ts").then((m) => new m.KiroExecutor("amazon-q")),
bedrock: () => import("./bedrock.ts").then((m) => new m.BedrockExecutor()),
codex: () => import("./codex.ts").then((m) => new m.CodexExecutor()),
"codex-app-server": () =>
import("./codex-app-server.ts").then(
(m) => new m.CodexAppServerExecutor({}, "codex-app-server")
),
"chatgpt-web-codex": () =>
import("./chatgpt-web-codex.ts").then((m) => new m.ChatGptWebCodexExecutor()),
"cgpt-codex": () =>
import("./chatgpt-web-codex.ts").then((m) => new m.ChatGptWebCodexExecutor()),
cursor: () => import("./cursor.ts").then((m) => new m.CursorExecutor()),
trae: () => import("./trae.ts").then((m) => new m.TraeExecutor()),
glm: () => import("./glm.ts").then((m) => new m.GlmExecutor("glm")),
"glm-cn": () => import("./glm.ts").then((m) => new m.GlmExecutor("glm-cn")),
glmt: () => import("./glm.ts").then((m) => new m.GlmExecutor("glmt")),
cu: () => import("./cursor.ts").then((m) => new m.CursorExecutor()), // Alias for cursor
"cursor-api": () => import("./cursor.ts").then((m) => new m.CursorExecutor("cursor-api")),
cua: () => import("./cursor.ts").then((m) => new m.CursorExecutor("cursor-api")),
"azure-openai": () => import("./azure-openai.ts").then((m) => new m.AzureOpenAIExecutor()),
"azure-ai": () => import("./azure-ai.ts").then((m) => new m.AzureAiExecutor()),
"command-code": () => import("./commandCode.ts").then((m) => new m.CommandCodeExecutor()),
cmd: () => import("./commandCode.ts").then((m) => new m.CommandCodeExecutor()), // Alias
gitlab: () => import("./gitlab.ts").then((m) => new m.GitlabExecutor()),
"gitlab-duo": () => import("./gitlab.ts").then((m) => new m.GitlabExecutor("gitlab-duo")),
nlpcloud: () => import("./nlpcloud.ts").then((m) => new m.NlpCloudExecutor()),
pollinations: () => import("./pollinations.ts").then((m) => new m.PollinationsExecutor()),
pol: () => import("./pollinations.ts").then((m) => new m.PollinationsExecutor()), // Alias
"cloudflare-ai": () => import("./cloudflare-ai.ts").then((m) => new m.CloudflareAIExecutor()),
cf: () => import("./cloudflare-ai.ts").then((m) => new m.CloudflareAIExecutor()), // Alias
freebuff: () => import("./freebuff.ts").then((m) => new m.FreebuffExecutor()),
fb: () => import("./freebuff.ts").then((m) => new m.FreebuffExecutor()), // Alias
"opencode-zen": () =>
import("./opencode.ts").then((m) => new m.OpencodeExecutor("opencode-zen")),
"opencode-go": () =>
import("./opencode.ts").then((m) => new m.OpencodeExecutor("opencode-go")),
opencode: () =>
import("./opencode.ts").then((m) => new m.OpencodeExecutor("opencode-zen")), // Alias for opencode-zen
vertex: () => import("./vertex.ts").then((m) => new m.VertexExecutor()),
"vertex-partner": () => import("./vertex.ts").then((m) => new m.VertexExecutor()),
cliproxyapi: () => import("./cliproxyapi.ts").then((m) => new m.CliproxyapiExecutor()),
cpa: () => import("./cliproxyapi.ts").then((m) => new m.CliproxyapiExecutor()), // Alias
dario: () => import("./dario.ts").then((m) => new m.DarioExecutor()),
dr: () => import("./dario.ts").then((m) => new m.DarioExecutor()), // Alias
"9router": () => import("./ninerouter.ts").then((m) => new m.NineRouterExecutor()),
nr: () => import("./ninerouter.ts").then((m) => new m.NineRouterExecutor()), // Alias
"perplexity-web": () =>
import("./perplexity-web.ts").then((m) => new m.PerplexityWebExecutor()),
"pplx-web": () =>
import("./perplexity-web.ts").then((m) => new m.PerplexityWebExecutor()), // Alias
"grok-web": () => import("./grok-web.ts").then((m) => new m.GrokWebExecutor()),
"claude-web": () => import("./claude-web.ts").then((m) => new m.ClaudeWebExecutor()),
"cw-web": () => import("./claude-web.ts").then((m) => new m.ClaudeWebExecutor()), // Alias
"gemini-web": () => import("./gemini-web.ts").then((m) => new m.GeminiWebExecutor()),
gweb: () => import("./gemini-web.ts").then((m) => new m.GeminiWebExecutor()), // Alias
"gemini-business": () =>
import("./gemini-business.ts").then((m) => new m.GeminiBusinessExecutor()),
gembiz: () =>
import("./gemini-business.ts").then((m) => new m.GeminiBusinessExecutor()), // Alias
"chatgpt-web": () => import("./chatgpt-web.ts").then((m) => new m.ChatGptWebExecutor()),
"cgpt-web": () => import("./chatgpt-web.ts").then((m) => new m.ChatGptWebExecutor()), // Alias
"blackbox-web": () => import("./blackbox-web.ts").then((m) => new m.BlackboxWebExecutor()),
"bb-web": () => import("./blackbox-web.ts").then((m) => new m.BlackboxWebExecutor()), // Alias
"muse-spark-web": () =>
import("./muse-spark-web.ts").then((m) => new m.MuseSparkWebExecutor()),
"ms-web": () => import("./muse-spark-web.ts").then((m) => new m.MuseSparkWebExecutor()), // Alias
"devin-desktop": () => import("./devin-desktop.ts").then((m) => new m.DevinDesktopExecutor()),
"zed-hosted": () => import("./zed-hosted.ts").then((m) => new m.ZedHostedExecutor()),
"devin-cli": () => import("./devin-cli.ts").then((m) => new m.DevinCliExecutor()),
zcode: () => import("./zcode.ts").then((m) => new m.ZcodeExecutor()),
zc: () => import("./zcode.ts").then((m) => new m.ZcodeExecutor()), // Alias
"devin-cli-agentic": () =>
import("./devin-cli-agentic.ts").then((m) => new m.DevinCliAgenticExecutor()),
devin: () => import("./devin-cli.ts").then((m) => new m.DevinCliExecutor()), // Alias
"deepseek-web": () =>
import("./deepseek-web-with-auto-refresh.ts").then(
(m) => new m.DeepSeekWebWithAutoRefreshExecutor()
),
"ds-web": () =>
import("./deepseek-web-with-auto-refresh.ts").then(
(m) => new m.DeepSeekWebWithAutoRefreshExecutor()
), // Alias
"adapta-web": () => import("./adapta-web.ts").then((m) => new m.AdaptaWebExecutor()),
"adp-web": () => import("./adapta-web.ts").then((m) => new m.AdaptaWebExecutor()), // Alias
"copilot-web": () => import("./copilot-web.ts").then((m) => new m.CopilotWebExecutor()),
"copilot-m365-web": () =>
import("./copilot-m365-web.ts").then((m) => new m.CopilotM365WebExecutor()),
copilot: () => import("./copilot-web.ts").then((m) => new m.CopilotWebExecutor()), // Alias
"microsoft-designer-web": () =>
import("./microsoft-designer-web.ts").then((m) => new m.MicrosoftDesignerWebExecutor()),
msdesigner: () =>
import("./microsoft-designer-web.ts").then((m) => new m.MicrosoftDesignerWebExecutor()), // Alias
"adobe-firefly": () => import("./adobe-firefly.ts").then((m) => new m.AdobeFireflyExecutor()),
firefly: () => import("./adobe-firefly.ts").then((m) => new m.AdobeFireflyExecutor()), // Alias
"veoaifree-web": () => import("./veoaifree-web.ts").then((m) => new m.VeoAIFreeWebExecutor()),
"veo-free": () => import("./veoaifree-web.ts").then((m) => new m.VeoAIFreeWebExecutor()), // Alias
"duckduckgo-web": () =>
import("./duckduckgo-web.ts").then((m) => new m.DuckDuckGoWebExecutor()),
ddgw: () => import("./duckduckgo-web.ts").then((m) => new m.DuckDuckGoWebExecutor()), // Alias
"felo-web": () => import("./felo-web.ts").then((m) => new m.FeloWebExecutor()),
felo: () => import("./felo-web.ts").then((m) => new m.FeloWebExecutor()), // Alias
"t3-web": () => import("./t3-chat-web.ts").then((m) => new m.T3ChatWebExecutor()),
t3chat: () => import("./t3-chat-web.ts").then((m) => new m.T3ChatWebExecutor()), // Alias
"inner-ai": () => import("./inner-ai.ts").then((m) => new m.InnerAiExecutor()),
"in-ai": () => import("./inner-ai.ts").then((m) => new m.InnerAiExecutor()), // Alias
huggingchat: () => import("./huggingchat.ts").then((m) => new m.HuggingChatExecutor()),
hc: () => import("./huggingchat.ts").then((m) => new m.HuggingChatExecutor()), // Alias
"yuanbao-web": () => import("./yuanbao-web.ts").then((m) => new m.YuanbaoWebExecutor()),
"tencent-aistudio-web": () =>
import("./tencent-aistudio-web.ts").then((m) => new m.TencentAIStudioWebExecutor()),
tasw: () =>
import("./tencent-aistudio-web.ts").then((m) => new m.TencentAIStudioWebExecutor()), // Alias
ybw: () => import("./yuanbao-web.ts").then((m) => new m.YuanbaoWebExecutor()), // Alias
"poe-web": () => import("./poe-web.ts").then((m) => new m.PoeWebExecutor()),
// #8969: do NOT alias canonical `poe` (API-key / api.poe.com) to PoeWebExecutor.
// Registry declares executor:"default"; the hard-coded map previously won and
// routed API-key traffic to GraphQL /api/gql_POST → HTTP 405.
"venice-web": new VeniceWebExecutor(),
ven: new VeniceWebExecutor(), // Alias
"notion-web": new NotionWebExecutor(),
nw: new NotionWebExecutor(), // Alias
promptql: new PromptQlExecutor(),
pql: new PromptQlExecutor(), // Alias
"v0-vercel-web": new V0VercelWebExecutor(),
v0: new V0VercelWebExecutor(), // Alias
"kimi-web": new KimiWebExecutor(),
"kimi-coding-apikey": new KimiExecutor("kimi-coding-apikey"), // Legacy alias
"kimi-coding": new KimiExecutor(), // Alias
moonshot: new MoonshotExecutor(),
kimi: new MoonshotExecutor("kimi"), // Hidden legacy Moonshot provider id
cheaperinference: new CheaperInferenceExecutor(),
cinf: new CheaperInferenceExecutor("cheaperinference"), // Alias
"doubao-web": new DoubaoWebExecutor(),
db: new DoubaoWebExecutor(), // Alias
"qwen-web": new QwenWebExecutor(),
raycast: new RaycastExecutor(),
rc: new RaycastExecutor(), // Alias
"hailuo-web": new HailuoWebExecutor(),
"zai-web": new ZaiWebExecutor(),
zw: new ZaiWebExecutor(), // Alias
theoldllm: new TheOldLlmExecutor(),
tllm: new TheOldLlmExecutor(), // Alias
chipotle: new ChipotleExecutor(),
pepper: new ChipotleExecutor(), // Alias
lmarena: new LMArenaExecutor(),
lma: new LMArenaExecutor(), // Alias
"grok-cli": new GrokCliExecutor(),
gc: new GrokCliExecutor(), // Alias
"codebuddy-cn": new CodeBuddyCnExecutor(),
cbcn: new CodeBuddyCnExecutor(), // Alias for codebuddy-cn
"zenmux-free": new ZenmuxFreeExecutor(),
"cloudflare-playground": new CloudflarePlaygroundExecutor(),
cfp: new CloudflarePlaygroundExecutor(), // Alias for cloudflare-playground
"tinycms-web": new TinyCmsExecutor(),
tcw: new TinyCmsExecutor(), // Alias
hyperagent: new HyperAgentExecutor(),
ha: new HyperAgentExecutor(), // Alias
zmf: new ZenmuxFreeExecutor(), // Alias for zenmux-free
auggie: new AuggieExecutor(),
xai: new XaiExecutor(),
"xai-oauth": new XaiExecutor("xai-oauth"),
xao: new XaiExecutor("xai-oauth"),
qw: new QwenWebExecutor(), // Alias
"conol-web": new ConolWebExecutor(),
cnl: new ConolWebExecutor(), // Alias
"venice-web": () => import("./venice-web.ts").then((m) => new m.VeniceWebExecutor()),
ven: () => import("./venice-web.ts").then((m) => new m.VeniceWebExecutor()), // Alias
"notion-web": () => import("./notion-web.ts").then((m) => new m.NotionWebExecutor()),
nw: () => import("./notion-web.ts").then((m) => new m.NotionWebExecutor()), // Alias
promptql: () => import("./promptql.ts").then((m) => new m.PromptQlExecutor()),
pql: () => import("./promptql.ts").then((m) => new m.PromptQlExecutor()), // Alias
"v0-vercel-web": () => import("./v0-vercel-web.ts").then((m) => new m.V0VercelWebExecutor()),
v0: () => import("./v0-vercel-web.ts").then((m) => new m.V0VercelWebExecutor()), // Alias
"kimi-web": () => import("./kimi-web.ts").then((m) => new m.KimiWebExecutor()),
"kimi-coding-apikey": () =>
import("./kimi.ts").then((m) => new m.KimiExecutor("kimi-coding-apikey")), // Legacy alias
"kimi-coding": () => import("./kimi.ts").then((m) => new m.KimiExecutor()), // Alias
moonshot: () => import("./moonshot.ts").then((m) => new m.MoonshotExecutor()),
kimi: () => import("./moonshot.ts").then((m) => new m.MoonshotExecutor("kimi")), // Hidden legacy Moonshot provider id
cheaperinference: () =>
import("./cheaperinference.ts").then((m) => new m.CheaperInferenceExecutor()),
cinf: () =>
import("./cheaperinference.ts").then(
(m) => new m.CheaperInferenceExecutor("cheaperinference")
), // Alias
"doubao-web": () => import("./doubao-web.ts").then((m) => new m.DoubaoWebExecutor()),
db: () => import("./doubao-web.ts").then((m) => new m.DoubaoWebExecutor()), // Alias
"qwen-web": () => import("./qwen-web.ts").then((m) => new m.QwenWebExecutor()),
raycast: () => import("./raycast.ts").then((m) => new m.RaycastExecutor()),
rc: () => import("./raycast.ts").then((m) => new m.RaycastExecutor()), // Alias
"hailuo-web": () => import("./hailuo-web.ts").then((m) => new m.HailuoWebExecutor()),
"zai-web": () => import("./zai-web.ts").then((m) => new m.ZaiWebExecutor()),
zw: () => import("./zai-web.ts").then((m) => new m.ZaiWebExecutor()), // Alias
theoldllm: () => import("./theoldllm.ts").then((m) => new m.TheOldLlmExecutor()),
tllm: () => import("./theoldllm.ts").then((m) => new m.TheOldLlmExecutor()), // Alias
chipotle: () => import("./chipotle.ts").then((m) => new m.ChipotleExecutor()),
pepper: () => import("./chipotle.ts").then((m) => new m.ChipotleExecutor()), // Alias
lmarena: () => import("./lmarena.ts").then((m) => new m.LMArenaExecutor()),
lma: () => import("./lmarena.ts").then((m) => new m.LMArenaExecutor()), // Alias
"grok-cli": () => import("./grok-cli.ts").then((m) => new m.GrokCliExecutor()),
gc: () => import("./grok-cli.ts").then((m) => new m.GrokCliExecutor()), // Alias
"codebuddy-cn": () => import("./codebuddy-cn.ts").then((m) => new m.CodeBuddyCnExecutor()),
cbcn: () => import("./codebuddy-cn.ts").then((m) => new m.CodeBuddyCnExecutor()), // Alias for codebuddy-cn
"zenmux-free": () => import("./zenmux-free.ts").then((m) => new m.ZenmuxFreeExecutor()),
"cloudflare-playground": () =>
import("./cloudflare-playground.ts").then((m) => new m.CloudflarePlaygroundExecutor()),
cfp: () =>
import("./cloudflare-playground.ts").then((m) => new m.CloudflarePlaygroundExecutor()), // Alias for cloudflare-playground
"tinycms-web": () => import("./tinycms.ts").then((m) => new m.TinyCmsExecutor()),
tcw: () => import("./tinycms.ts").then((m) => new m.TinyCmsExecutor()), // Alias
hyperagent: () => import("./hyperagent.ts").then((m) => new m.HyperAgentExecutor()),
ha: () => import("./hyperagent.ts").then((m) => new m.HyperAgentExecutor()), // Alias
zmf: () => import("./zenmux-free.ts").then((m) => new m.ZenmuxFreeExecutor()), // Alias for zenmux-free
auggie: () => import("./auggie.ts").then((m) => new m.AuggieExecutor()),
xai: () => import("./xai.ts").then((m) => new m.XaiExecutor()),
"xai-oauth": () => import("./xai.ts").then((m) => new m.XaiExecutor("xai-oauth")),
xao: () => import("./xai.ts").then((m) => new m.XaiExecutor("xai-oauth")),
qw: () => import("./qwen-web.ts").then((m) => new m.QwenWebExecutor()), // Alias
"conol-web": () => import("./conol-web.ts").then((m) => new m.ConolWebExecutor()),
cnl: () => import("./conol-web.ts").then((m) => new m.ConolWebExecutor()), // Alias
};
// Bootstrap: register every built-in in the ExecutorRegistry. registerExecutor
// throws on duplicates, so an alias collision fails at module load, exactly as
// loudly as a duplicate object key would have failed at lint time.
for (const [alias, executor] of Object.entries(executors) as [string, BaseExecutor][]) {
registerExecutor(alias, executor);
// Bootstrap: declare every built-in alias in the ExecutorRegistry. Duplicate
// aliases fail at module load, exactly as loudly as a duplicate object key
// would have failed at lint time. Instances materialize on first use (#11220).
for (const [alias, load] of Object.entries(lazyExecutors)) {
registerLazyExecutor(alias, load);
}
const defaultCache = new Map();
@@ -267,9 +239,9 @@ const CHAT_UNSUPPORTED_CLOUD_AGENT_PROVIDERS = new Set(["jules"]);
// providers must be executed through /v1/search, never the chat-completions path.
const CHAT_UNSUPPORTED_SEARCH_PROVIDERS = new Set(Object.keys(SEARCH_PROVIDERS));
export function getExecutor(provider) {
const registered = getRegisteredExecutor(provider);
if (registered) return registered;
export async function getExecutor(provider: string): Promise<BaseExecutor> {
const loaded = await loadRegisteredExecutor(provider);
if (loaded) return loaded;
if (CHAT_UNSUPPORTED_CLOUD_AGENT_PROVIDERS.has(provider)) {
const err = new Error(
`Provider "${provider}" is a cloud-agent provider and does not support direct chat completions; use the Cloud Agents task API instead.`
@@ -285,77 +257,19 @@ export function getExecutor(provider) {
throw err;
}
if (!defaultCache.has(provider)) defaultCache.set(provider, new DefaultExecutor(provider));
return defaultCache.get(provider);
return defaultCache.get(provider)!;
}
export function hasSpecializedExecutor(provider) {
export function hasSpecializedExecutor(provider: string): boolean {
return hasRegisteredExecutor(provider);
}
export { registerExecutor, listExecutorAliases } from "./registry.ts";
export {
registerExecutor,
registerLazyExecutor,
listExecutorAliases,
} from "./registry.ts";
// Value re-export: base.ts is already eager (DefaultExecutor extends it), and
// scripts/check/check-known-symbols.ts reads this export from the module.
export { BaseExecutor } from "./base.ts";
export { AntigravityExecutor } from "./antigravity.ts";
export { GithubExecutor } from "./github.ts";
export { QoderExecutor } from "./qoder.ts";
export { KiroExecutor } from "./kiro.ts";
export { CodexExecutor } from "./codex.ts";
export { CursorExecutor } from "./cursor.ts";
export { TraeExecutor } from "./trae.ts";
export { DefaultExecutor } from "./default.ts";
export { BedrockExecutor } from "./bedrock.ts";
export { GlmExecutor } from "./glm.ts";
export { PollinationsExecutor } from "./pollinations.ts";
export { CloudflareAIExecutor } from "./cloudflare-ai.ts";
export { OpencodeExecutor } from "./opencode.ts";
export { CliproxyapiExecutor } from "./cliproxyapi.ts";
export { DarioExecutor } from "./dario.ts";
export { NineRouterExecutor } from "./ninerouter.ts";
export { VertexExecutor } from "./vertex.ts";
export { PerplexityWebExecutor } from "./perplexity-web.ts";
export { GrokWebExecutor } from "./grok-web.ts";
export { GeminiWebExecutor } from "./gemini-web.ts";
export { KieExecutor } from "./kie.ts";
export { ChatGptWebExecutor } from "./chatgpt-web.ts";
export { BlackboxWebExecutor } from "./blackbox-web.ts";
export { MuseSparkWebExecutor } from "./muse-spark-web.ts";
export { AzureOpenAIExecutor } from "./azure-openai.ts";
export { AzureAiExecutor } from "./azure-ai.ts";
export { CommandCodeExecutor } from "./commandCode.ts";
export { GitlabExecutor } from "./gitlab.ts";
export { NlpCloudExecutor } from "./nlpcloud.ts";
export { DevinDesktopExecutor } from "./devin-desktop.ts";
export { ZedHostedExecutor } from "./zed-hosted.ts";
export { DevinCliExecutor } from "./devin-cli.ts";
export { DevinCliAgenticExecutor } from "./devin-cli-agentic.ts";
export { AuggieExecutor } from "./auggie.ts";
export { CopilotWebExecutor } from "./copilot-web.ts";
export { CopilotM365WebExecutor } from "./copilot-m365-web.ts";
export { MicrosoftDesignerWebExecutor } from "./microsoft-designer-web.ts";
export { AdobeFireflyExecutor } from "./adobe-firefly.ts";
export { VeoAIFreeWebExecutor } from "./veoaifree-web.ts";
export { DuckDuckGoWebExecutor } from "./duckduckgo-web.ts";
export { FeloWebExecutor } from "./felo-web.ts";
export { ClaudeWebExecutor } from "./claude-web.ts";
export { DeepSeekWebExecutor } from "./deepseek-web.ts";
export { DeepSeekWebWithAutoRefreshExecutor } from "./deepseek-web-with-auto-refresh.ts";
export { AdaptaWebExecutor } from "./adapta-web.ts";
export { YuanbaoWebExecutor } from "./yuanbao-web.ts";
export { T3ChatWebExecutor } from "./t3-chat-web.ts";
export { InnerAiExecutor } from "./inner-ai.ts";
export { QwenWebExecutor } from "./qwen-web.ts";
export { HailuoWebExecutor } from "./hailuo-web.ts";
export { TheOldLlmExecutor } from "./theoldllm.ts";
export { ChipotleExecutor } from "./chipotle.ts";
export { LMArenaExecutor } from "./lmarena.ts";
export { GrokCliExecutor } from "./grok-cli.ts";
export { CodeBuddyCnExecutor } from "./codebuddy-cn.ts";
export { ZenmuxFreeExecutor } from "./zenmux-free.ts";
export { CloudflarePlaygroundExecutor } from "./cloudflare-playground.ts";
export { TinyCmsExecutor } from "./tinycms.ts";
export { HyperAgentExecutor } from "./hyperagent.ts";
export { XaiExecutor } from "./xai.ts";
export { MoonshotExecutor } from "./moonshot.ts";
export { CheaperInferenceExecutor } from "./cheaperinference.ts";
export { PromptQlExecutor } from "./promptql.ts";
export { ConolWebExecutor } from "./conol-web.ts";

View File

@@ -895,10 +895,21 @@ export class OpencodeExecutor extends BaseExecutor {
const mb = modifiedBody as Record<string, unknown>;
const parsed = parseEffortLevel(model);
if (parsed) {
mb.model = parsed.baseModel;
if (mb.reasoning_effort === undefined) {
mb.reasoning_effort = parsed.effort;
const deepseekFamily =
parsed.baseModel === "deepseek-v4-pro" || parsed.baseModel === "deepseek-v4-flash";
if (deepseekFamily) {
// DeepSeek via opencode-go proxies the native DeepSeek contract, which
// accepts a flat reasoning_effort field (#4647).
mb.model = parsed.baseModel;
if (mb.reasoning_effort === undefined) {
mb.reasoning_effort = parsed.effort;
}
}
// #10788: every other family's ONLY native effort mechanism is the
// -<tier> suffix in the model id itself (the ids `opencode models
// opencode-go --verbose` lists). The opencode-go ChatCompletionRequest
// carries no flat reasoning_effort field, so rewriting to the base id
// silently dropped the tier — forward the aliased id verbatim instead.
}
}
// #1543 / upstream PR #1099: thinking-mode upstreams routed through OpenCode

View File

@@ -28,11 +28,46 @@ export function getRegisteredExecutor(alias: string): BaseExecutor | undefined {
return registry.get(alias);
}
export function hasRegisteredExecutor(alias: string): boolean {
return registry.has(alias);
// ── #11220: lazy registration ───────────────────────────────────────────────
// Aliases may register a deferred loader instead of an instance. The alias and
// its registration ORDER are declared eagerly — hasRegisteredExecutor() and
// listExecutorAliases() stay synchronous and the golden snapshot keeps its
// shape — while the class import + construction happen on first use. A
// completed load caches into `registry`, so later resolution is identical to a
// static registration.
const lazyLoaders = new Map<string, () => Promise<BaseExecutor>>();
const lazyInFlight = new Map<string, Promise<BaseExecutor>>();
export function registerLazyExecutor(alias: string, load: () => Promise<BaseExecutor>): void {
if (registry.has(alias) || lazyLoaders.has(alias)) {
throw new Error(`executor alias already registered: "${alias}"`);
}
lazyLoaders.set(alias, load);
}
/** All registered aliases, in registration order. */
export function loadRegisteredExecutor(alias: string): Promise<BaseExecutor> | undefined {
const cached = registry.get(alias);
if (cached) return Promise.resolve(cached);
const load = lazyLoaders.get(alias);
if (!load) return undefined;
let inFlight = lazyInFlight.get(alias);
if (!inFlight) {
inFlight = load().then((executor) => {
registerExecutor(alias, executor);
lazyLoaders.delete(alias);
lazyInFlight.delete(alias);
return executor;
});
lazyInFlight.set(alias, inFlight);
}
return inFlight;
}
export function hasRegisteredExecutor(alias: string): boolean {
return registry.has(alias) || lazyLoaders.has(alias);
}
/** All registered aliases — static and lazy — in registration order. */
export function listExecutorAliases(): string[] {
return [...registry.keys()];
return [...registry.keys(), ...lazyLoaders.keys()];
}

View File

@@ -396,7 +396,7 @@ import {
} from "../services/rateLimitManager.ts";
import * as localLimiterErrors from "../services/rateLimitManager/errors.ts";
import {
acquire as acquireAccountSemaphore,
acquireMany as acquireConcurrencyGates,
markBlocked as markAccountSemaphoreBlocked,
} from "../services/accountSemaphore.ts";
import { lockModel, lockModelIfPerModelQuota } from "../services/accountFallback.ts";
@@ -447,6 +447,7 @@ import { extractFacts } from "@/lib/memory/extraction";
import { handleToolCallExecution } from "@/lib/skills/interception";
import { MEMORY_BUILTIN_TOOL_NAMES } from "@/lib/skills/memoryBuiltins";
import { OMNIROUTE_RESPONSE_HEADERS } from "@/shared/constants/headers";
import { resolveProviderId } from "@/shared/constants/providers";
import { getClaudeCodeCompatibleRequestDefaults } from "@/lib/providers/requestDefaults";
import {
buildClaudeCodeCompatibleRequest,
@@ -525,6 +526,7 @@ export async function handleChatCore({
managedLease = null,
}) {
let { provider, model, extendedContext } = modelInfo;
const resilienceSettings = resolveResilienceSettings(cachedSettings);
if (!skipResourcePressureGuard) {
try {
const pressureGuard = checkResourcePressureGuard();
@@ -3051,6 +3053,10 @@ export async function handleChatCore({
connectionId: attemptConnectionId,
credentials: execCreds,
});
const canonicalProviderKey = resolveProviderId(String(provider).trim().toLowerCase());
const providerConcurrency =
resilienceSettings.providerQuotaOverrides[canonicalProviderKey]
?.providerConcurrency ?? 0;
trace("pre_semaphore", {
semaphoreKey: accountSemaphoreKey,
@@ -3061,13 +3067,27 @@ export async function handleChatCore({
stage: "waiting_account_slot",
});
}
const releaseAccountSemaphore =
accountSemaphoreKey && accountSemaphoreMaxConcurrency != null
? await acquireAccountSemaphore(accountSemaphoreKey, {
maxConcurrency: accountSemaphoreMaxConcurrency,
signal: streamController.signal,
})
: () => {};
const releaseAccountSemaphore = await acquireConcurrencyGates(
[
{
key: "global",
maxConcurrency: resilienceSettings.requestQueue.globalConcurrentRequests,
},
{
key: `provider:${canonicalProviderKey}`,
maxConcurrency: providerConcurrency,
},
{
key: accountSemaphoreKey || "",
maxConcurrency: accountSemaphoreKey ? accountSemaphoreMaxConcurrency : null,
},
],
{
timeoutMs: resilienceSettings.requestQueue.maxWaitMs,
maxQueueSize: resilienceSettings.requestQueue.maxQueueDepth,
signal: streamController.signal,
}
);
trace("post_semaphore");
updatePendingScope(pendingScope, {
stage: "waiting_rate_limit",
@@ -3328,6 +3348,7 @@ export async function handleChatCore({
"ANTIGRAVITY_BYOP_ROTATION",
`BYOP 422 on connection ${String(byopFailedId).slice(0, 8)} → rotating to ${String(byopNextCreds.connectionId).slice(0, 8)}`
);
releaseAccountSemaphore();
Object.assign(credentials, byopNextCreds);
antigravityByopRotationPending = true;
continue;

View File

@@ -14,12 +14,12 @@
type ExecutorInput = {
model: string;
body: unknown;
[key: string]: unknown;
};
// No index signature: executors (BaseExecutor subclasses) must satisfy this
// structurally, and class instances don't carry index signatures.
type ExecutorLike = {
execute: (input: ExecutorInput) => Promise<unknown>;
[key: string]: unknown;
};
export type CliproxyapiModelMapping = Record<string, unknown> | null | undefined;

View File

@@ -19,12 +19,12 @@ import type { ProviderCredentials } from "../../executors/base.ts";
type ExecutorInput = {
credentials: ProviderCredentials;
[key: string]: unknown;
};
// No index signature: executors (BaseExecutor subclasses) must satisfy this
// structurally, and class instances don't carry index signatures.
type ExecutorLike = {
execute: (input: ExecutorInput) => Promise<unknown>;
[key: string]: unknown;
};
/**

View File

@@ -76,12 +76,15 @@ async function loadCliproxyapiSettings(): Promise<{
* dedicated-credential wrappers applied. Used by the direct `cliproxyapi` leg
* and the CLIProxyAPI branch of `fallback`.
*/
function resolveCliproxyapiExecutor(
async function resolveCliproxyapiExecutor(
cliproxyapiModelMapping: Record<string, unknown> | null,
dedicatedApiKey: string | null
) {
return wrapExecutorWithCliproxyapiCredentials(
wrapExecutorWithCliproxyapiModelMapping(getExecutor("cliproxyapi"), cliproxyapiModelMapping),
wrapExecutorWithCliproxyapiModelMapping(
await getExecutor("cliproxyapi"),
cliproxyapiModelMapping
),
dedicatedApiKey
);
}
@@ -138,7 +141,7 @@ export async function resolveExecutorWithProxy(
// backend on specific failures. The backend defaults to CLIProxyAPI so every
// pre-existing fallback config behaves exactly as before; fallbackBackend
// === "dario" opts the retry leg over to Dario instead.
const nativeExec = getExecutor(prov);
const nativeExec = await getExecutor(prov);
const fallbackBackend: FallbackBackend = cfg.fallbackBackend;
const { fallbackCodes, dedicatedApiKey } = await loadCliproxyapiSettings();
@@ -146,8 +149,8 @@ export async function resolveExecutorWithProxy(
// the native leg must keep seeing the original, unmapped model.
const proxyExec =
fallbackBackend === "dario"
? getExecutor("dario")
: resolveCliproxyapiExecutor(cfg.cliproxyapiModelMapping, dedicatedApiKey);
? await getExecutor("dario")
: await resolveCliproxyapiExecutor(cfg.cliproxyapiModelMapping, dedicatedApiKey);
const backendLabel = fallbackBackend === "dario" ? "Dario" : "CLIProxyAPI";
const isRetryableStatus = (s: number) => fallbackCodes.includes(s) || s === 0;

View File

@@ -201,6 +201,7 @@ export async function handleRerank({
connectionId = null,
apiKeyId = null,
apiKeyName = null,
resolvedProvider = null,
}) {
const startTime = Date.now();
if (!model) return errorResponse(400, "model is required");
@@ -210,7 +211,8 @@ export async function handleRerank({
}
const { provider: providerId, model: modelId } = parseRerankModel(model);
const providerConfig = providerId ? getRerankProvider(providerId) : null;
const providerConfig =
resolvedProvider || (providerId ? getRerankProvider(providerId) : null);
if (!providerConfig) {
const availableProviders = Object.keys(RERANK_PROVIDERS).join(", ");
@@ -219,10 +221,13 @@ export async function handleRerank({
`No rerank provider found for model "${model}". Available: ${availableProviders}`
);
}
// When a derived/generic provider is injected, its id is authoritative for
// logging and cost attribution even though parseRerankModel returned null.
const effectiveProviderId = providerConfig.id || providerId;
const token = credentials?.apiKey || credentials?.accessToken;
if (!token) {
return errorResponse(401, `No credentials for rerank provider: ${providerId}`);
return errorResponse(401, `No credentials for rerank provider: ${effectiveProviderId}`);
}
const requestBody = transformRequestForProvider(providerConfig, {
@@ -275,8 +280,8 @@ export async function handleRerank({
method: "POST",
path: "/v1/rerank",
status: res.status,
model: `${providerId}/${modelId}`,
provider: providerId,
model: `${effectiveProviderId}/${modelId}`,
provider: effectiveProviderId,
connectionId: connectionId || undefined,
duration: Date.now() - startTime,
requestBody,
@@ -296,14 +301,14 @@ export async function handleRerank({
});
const searchUnits = Number(result?.meta?.billed_units?.search_units) || 0;
const costUsd = await calculateModalCost("rerank", providerId, modelId, { searchUnits });
const costUsd = await calculateModalCost("rerank", effectiveProviderId, modelId, { searchUnits });
saveCallLog({
method: "POST",
path: "/v1/rerank",
status: 200,
model: `${providerId}/${modelId}`,
provider: providerId,
model: `${effectiveProviderId}/${modelId}`,
provider: effectiveProviderId,
connectionId: connectionId || undefined,
duration: Date.now() - startTime,
tokens: { prompt_tokens: 0, completion_tokens: 0 },
@@ -315,7 +320,7 @@ export async function handleRerank({
const headers = new Headers({ ...CORS_HEADERS, "Content-Type": "application/json" });
attachOmniRouteMetaHeaders(headers, {
provider: providerId,
provider: effectiveProviderId,
model: modelId,
costUsd,
latencyMs: Date.now() - startTime,

View File

@@ -8,6 +8,7 @@ import { randomUUID } from "crypto";
* firecrawl, google-pse-search, linkup-search, searchapi-search,
* youcom-search, searxng-search, ollama-search, zai-search, jina-search,
* duckduckgo-free, x-search (Grok / SuperGrok X Search — explicit or search_type "x")
* and xquik-search (direct X API search — explicit or credentialed fallback)
*
* Request format:
* {
@@ -28,6 +29,7 @@ import * as fcSearch from "./search/firecrawlSearch.ts";
import { type FirecrawlSearchEnvelope } from "./search/firecrawlSearch.ts";
import { buildJinaSearchRequest, extractJinaSearchItems } from "./search/jinaSearch.ts";
import * as xSearch from "./search/xSearch.ts";
import * as xquikSearch from "./search/xquikSearch.ts";
import { freeWebSearch } from "../services/freeWebSearch.ts";
import { saveCallLog } from "@/lib/usageDb";
import { safeOutboundFetch } from "@/shared/network/safeOutboundFetch";
@@ -714,6 +716,7 @@ const requestBuilders: Record<string, SearchRequestBuilder> = {
"ollama-search": buildOllamaRequest,
"jina-search": buildJinaSearchRequest,
"x-search": xSearch.buildXSearchRequest,
"xquik-search": xquikSearch.buildXquikSearchRequest,
};
function buildRequest(
@@ -1290,6 +1293,7 @@ const responseNormalizers: Record<string, SearchResponseNormalizer> = {
"ollama-search": normalizeOllamaResponse,
"jina-search": normalizeJinaSearchResponse,
"x-search": normalizeXSearchResponse,
"xquik-search": (data) => xquikSearch.normalizeXquikSearchResponse(data, makeResult),
};
function normalizeResponse(

View File

@@ -0,0 +1,158 @@
/** Xquik-backed X search for the unified search gateway. */
import { z } from "zod";
import type { SearchProviderConfig } from "../../config/searchRegistry.ts";
import type { SearchResult } from "../search.ts";
export const XQUIK_SEARCH_PROVIDER_ID = "xquik-search";
export interface XquikSearchParams {
query: string;
maxResults: number;
token?: string;
timeRange?: string;
providerOptions?: Record<string, unknown>;
providerSpecificData?: Record<string, unknown>;
}
export interface XquikSearchHit {
title: string;
url: string;
snippet: string;
author?: string;
publishedAt?: string;
}
type MakeResult = (
providerId: string,
item: {
title?: string;
url?: string;
snippet?: string;
published_at?: string;
author?: string;
source_type?: string;
},
index: number,
now: string
) => SearchResult;
const X_HANDLE_RE = /^[A-Za-z0-9_]{1,15}$/;
const TWEET_ID_RE = /^\d+$/;
const XquikTweetSchema = z
.object({
id: z.string().regex(TWEET_ID_RE),
text: z.string(),
createdAt: z.string().optional(),
author: z
.object({
username: z.string().regex(X_HANDLE_RE),
name: z.string().optional(),
})
.passthrough()
.optional(),
})
.passthrough();
const XquikSearchEnvelopeSchema = z
.object({
tweets: z.array(z.unknown()).default([]),
})
.passthrough();
function getProviderSettingString(
params: Pick<XquikSearchParams, "providerOptions" | "providerSpecificData">,
key: string
): string | undefined {
const option = params.providerOptions?.[key];
if (typeof option === "string" && option.trim()) return option.trim();
const configured = params.providerSpecificData?.[key];
if (typeof configured === "string" && configured.trim()) return configured.trim();
return undefined;
}
function sinceTimeForRange(timeRange: string | undefined, now = Date.now()): string | undefined {
const hour = 60 * 60 * 1000;
const durations: Record<string, number> = {
hour,
day: 24 * hour,
week: 7 * 24 * hour,
month: 30 * 24 * hour,
year: 365 * 24 * hour,
};
const duration = timeRange ? durations[timeRange] : undefined;
return duration ? new Date(now - duration).toISOString() : undefined;
}
export function buildXquikSearchRequest(
config: SearchProviderConfig,
params: XquikSearchParams
): { url: string; init: RequestInit } {
const queryType = getProviderSettingString(params, "queryType") === "Top" ? "Top" : "Latest";
const query = new URLSearchParams({
q: params.query,
queryType,
limit: String(params.maxResults),
});
const sinceTime = sinceTimeForRange(params.timeRange);
if (sinceTime) query.set("sinceTime", sinceTime);
return {
url: `${config.baseUrl.replace(/\/+$/, "")}?${query}`,
init: {
method: "GET",
headers: {
Accept: "application/json",
...(params.token ? { "x-api-key": params.token } : {}),
},
},
};
}
export function extractXquikSearchHits(data: unknown, maxResults: number): XquikSearchHit[] {
const envelope = XquikSearchEnvelopeSchema.safeParse(data);
if (!envelope.success) return [];
const hits: XquikSearchHit[] = [];
for (const value of envelope.data.tweets) {
const parsed = XquikTweetSchema.safeParse(value);
if (!parsed.success) continue;
const tweet = parsed.data;
const author = tweet.author?.username;
hits.push({
title: author ? `@${author}` : "X post",
url: author
? `https://x.com/${author}/status/${tweet.id}`
: `https://x.com/i/status/${tweet.id}`,
snippet: tweet.text,
author,
publishedAt: tweet.createdAt,
});
if (hits.length >= maxResults) break;
}
return hits;
}
export function normalizeXquikSearchResponse(
data: unknown,
makeResult: MakeResult
): { results: SearchResult[]; totalResults: number } {
const now = new Date().toISOString();
const results = extractXquikSearchHits(data, 20).map((hit, index) =>
makeResult(
XQUIK_SEARCH_PROVIDER_ID,
{
title: hit.title,
url: hit.url,
snippet: hit.snippet,
published_at: hit.publishedAt,
author: hit.author,
source_type: "x",
},
index,
now
)
);
return { results, totalResults: results.length };
}

View File

@@ -374,7 +374,7 @@ async function handleVertexVeoGeneration({ model, body, credentials, log }) {
* Submits an AnimateDiff or SVD workflow, polls for completion, fetches output video
*/
async function handleVeoAiFreeVideoGeneration({ model, provider, body, credentials, log }) {
const executor = getExecutor(provider);
const executor = await getExecutor(provider);
if (!executor) {
return { success: false, status: 400, error: `Unknown video provider: ${provider}` };
}

View File

@@ -358,6 +358,38 @@ describe("omniroute_x_search handler (via MCP dispatch)", () => {
expect(body.search_type).toBe("x");
expect(body.provider).toBe("x-search");
});
it("should route an explicit Xquik search through xquik-search", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
id: "xs2",
provider: "xquik-search",
query: "agents sdk",
results: [
{
title: "@openai",
url: "https://x.com/openai/status/1912345678901234567",
snippet: "Agents SDK update",
position: 1,
},
],
cached: false,
usage: { queries_used: 1, search_cost_usd: 0.00015 },
}),
});
const result = await client.callTool({
name: "omniroute_x_search",
arguments: { query: "agents sdk", max_results: 5, provider: "xquik-search" },
});
expect(result.isError).toBeFalsy();
const [, options] = mockFetch.mock.calls[0];
const body = JSON.parse(options.body as string);
expect(body.search_type).toBe("x");
expect(body.provider).toBe("xquik-search");
});
});
// ── omniroute_get_health: handler dispatch tests ──────────────────────────────

View File

@@ -531,12 +531,17 @@ export const xSearchInput = z.object({
.max(20)
.default(5)
.describe("Maximum number of X results to return"),
provider: z
.enum(["x-search", "xquik-search"])
.optional()
.default("x-search")
.describe("X search backend: x-search uses xAI/SuperGrok; xquik-search uses Xquik"),
});
export const xSearchTool: McpToolDefinition<typeof xSearchInput, typeof webSearchOutput> = {
name: "omniroute_x_search",
description:
"Search X (Twitter) through OmniRoute using SuperGrok / xAI server-side x_search. Requires a connected xai-oauth (SuperGrok) or xAI API key. This is Grok X Search, not web search and not the X Developer Platform MCP.",
"Search X (Twitter) through OmniRoute. Uses SuperGrok / xAI server-side x_search by default, or Xquik when provider is xquik-search. Requires credentials for the selected backend. This is not web search.",
inputSchema: xSearchInput,
outputSchema: webSearchOutput,
scopes: ["execute:search"],

View File

@@ -666,7 +666,11 @@ async function handleWebSearch(args: {
}
}
async function handleXSearch(args: { query: string; max_results?: number }) {
async function handleXSearch(args: {
query: string;
max_results?: number;
provider?: "x-search" | "xquik-search";
}) {
const start = Date.now();
try {
const result = await omniRouteFetch("/v1/search", {
@@ -675,7 +679,7 @@ async function handleXSearch(args: { query: string; max_results?: number }) {
query: args.query,
max_results: args.max_results ?? 5,
search_type: "x",
provider: "x-search",
provider: args.provider ?? "x-search",
}),
signal: AbortSignal.timeout(120000),
});

View File

@@ -1,20 +1,40 @@
/**
* Account Semaphore
* Hierarchical in-memory concurrency admission.
*
* In-memory provider/account concurrency limiter keyed by provider and account.
* Requests beyond the configured concurrency cap wait in a FIFO queue until a slot opens,
* the gate is unblocked, or the queue timeout expires.
* `acquire()` preserves the account-semaphore API. `acquireMany()` admits one
* request only when every applicable global/provider/account gate has room.
*/
export interface AccountSemaphoreKeyParts {
provider: string;
accountKey: string;
}
interface QueuedAcquire {
export interface AcquireAccountSemaphoreOptions {
maxConcurrency?: number | null;
timeoutMs?: number;
signal?: AbortSignal | null;
maxQueueSize?: number;
}
export interface SemaphoreRequirement {
key: string;
maxConcurrency?: number | null;
}
export type AcquireManyOptions = Omit<AcquireAccountSemaphoreOptions, "maxConcurrency">;
interface AcquireRequest {
keys: string[];
resolve: (release: () => void) => void;
reject: (error: Error) => void;
timer: ReturnType<typeof setTimeout>;
timer: ReturnType<typeof setTimeout> | null;
signal: AbortSignal | null;
abortListener: (() => void) | null;
settled: boolean;
}
interface QueuedAcquire {
request: AcquireRequest;
}
interface AccountGate {
@@ -25,13 +45,6 @@ interface AccountGate {
cleanupTimer: ReturnType<typeof setTimeout> | null;
}
export interface AcquireAccountSemaphoreOptions {
maxConcurrency?: number | null;
timeoutMs?: number;
signal?: AbortSignal | null;
maxQueueSize?: number;
}
export interface AccountSemaphoreStatsEntry {
running: number;
queued: number;
@@ -41,12 +54,9 @@ export interface AccountSemaphoreStatsEntry {
const DEFAULT_TIMEOUT_MS = 30_000;
const DEFAULT_MAX_QUEUE_SIZE = 20;
const gates = new Map<string, AccountGate>();
const queuedRequests = new Set<AcquireRequest>();
/**
* Build the canonical account semaphore key.
*/
export function buildAccountSemaphoreKey({
provider,
accountKey,
@@ -55,25 +65,23 @@ export function buildAccountSemaphoreKey({
}
function isBypassed(maxConcurrency?: number | null): boolean {
return maxConcurrency == null || maxConcurrency <= 0;
return maxConcurrency == null || !Number.isFinite(maxConcurrency) || maxConcurrency <= 0;
}
function createNoopReleaseFn(): () => void {
let released = false;
return () => {
if (released) return;
released = true;
};
}
function ensureGate(semaphoreKey: string, maxConcurrency: number): AccountGate {
const existing = gates.get(semaphoreKey);
function ensureGate(key: string, maxConcurrency: number): AccountGate {
const existing = gates.get(key);
if (existing) {
existing.maxConcurrency = maxConcurrency;
return existing;
}
const created: AccountGate = {
running: 0,
maxConcurrency,
@@ -81,7 +89,7 @@ function ensureGate(semaphoreKey: string, maxConcurrency: number): AccountGate {
blockedUntil: null,
cleanupTimer: null,
};
gates.set(semaphoreKey, created);
gates.set(key, created);
return created;
}
@@ -100,91 +108,101 @@ function clearCleanupTimer(gate: AccountGate): void {
gate.cleanupTimer = null;
}
function cleanupGateIfIdle(semaphoreKey: string): void {
const gate = gates.get(semaphoreKey);
if (!gate) return;
if (gate.running > 0 || gate.queue.length > 0 || isBlocked(gate)) return;
function cleanupGateIfIdle(key: string): void {
const gate = gates.get(key);
if (!gate || gate.running > 0 || gate.queue.length > 0 || isBlocked(gate)) return;
clearCleanupTimer(gate);
gates.delete(semaphoreKey);
gates.delete(key);
}
function scheduleCleanup(semaphoreKey: string): void {
const gate = gates.get(semaphoreKey);
function scheduleCleanup(key: string): void {
const gate = gates.get(key);
if (!gate) return;
clearCleanupTimer(gate);
gate.cleanupTimer = setTimeout(() => {
gate.cleanupTimer = null;
cleanupGateIfIdle(semaphoreKey);
cleanupGateIfIdle(key);
}, 0);
gate.cleanupTimer.unref?.();
}
function drainQueue(semaphoreKey: string): void {
const gate = gates.get(semaphoreKey);
if (!gate) return;
while (gate.queue.length > 0 && gate.running < gate.maxConcurrency && !isBlocked(gate)) {
const next = gate.queue.shift();
if (!next) break;
clearTimeout(next.timer);
gate.running++;
next.resolve(createReleaseFn(semaphoreKey));
}
if (gate.running === 0 && gate.queue.length === 0) {
scheduleCleanup(semaphoreKey);
}
}
function createReleaseFn(semaphoreKey: string): () => void {
let released = false;
return () => {
if (released) return;
released = true;
const gate = gates.get(semaphoreKey);
if (!gate) return;
if (gate.running > 0) {
gate.running--;
}
if (gate.queue.length > 0) {
drainQueue(semaphoreKey);
return;
}
scheduleCleanup(semaphoreKey);
};
}
function createSemaphoreTimeoutError(
semaphoreKey: string,
timeoutMs: number
): Error & { code: string } {
const error = new Error(`Semaphore timeout after ${timeoutMs}ms for ${semaphoreKey}`) as Error & {
code: string;
};
error.code = "SEMAPHORE_TIMEOUT";
function makeAbortError(signal: AbortSignal): Error {
if (signal.reason instanceof Error) return signal.reason;
const error = new Error(
typeof signal.reason === "string" ? signal.reason : "The operation was aborted"
);
error.name = "AbortError";
return error;
}
function makeAbortError(signal: AbortSignal): Error {
const reason = signal.reason;
if (reason instanceof Error) return reason;
const err = new Error(typeof reason === "string" ? reason : "The operation was aborted");
err.name = "AbortError";
return err;
function createSemaphoreError(code: string, message: string): Error & { code: string } {
const error = new Error(message) as Error & { code: string };
error.code = code;
return error;
}
function removeRequest(request: AcquireRequest): void {
queuedRequests.delete(request);
if (request.timer) clearTimeout(request.timer);
if (request.abortListener && request.signal) {
request.signal.removeEventListener("abort", request.abortListener);
}
for (const key of request.keys) {
const gate = gates.get(key);
if (!gate) continue;
const index = gate.queue.findIndex((queued) => queued.request === request);
if (index >= 0) gate.queue.splice(index, 1);
if (gate.running === 0 && gate.queue.length === 0) scheduleCleanup(key);
}
}
function canAcquire(request: AcquireRequest): boolean {
return request.keys.every((key) => {
const gate = gates.get(key);
return (
gate != null &&
!isBlocked(gate) &&
gate.running < gate.maxConcurrency &&
gate.queue[0]?.request === request
);
});
}
function createCompositeReleaseFn(keys: string[]): () => void {
let released = false;
return () => {
if (released) return;
released = true;
for (const key of keys) {
const gate = gates.get(key);
if (gate && gate.running > 0) gate.running--;
}
drainQueues();
for (const key of keys) {
const gate = gates.get(key);
if (gate && gate.running === 0 && gate.queue.length === 0) scheduleCleanup(key);
}
};
}
function drainQueues(): void {
let progressed = true;
while (progressed) {
progressed = false;
for (const request of queuedRequests) {
if (request.settled || !canAcquire(request)) continue;
request.settled = true;
removeRequest(request);
for (const key of request.keys) gates.get(key)!.running++;
request.resolve(createCompositeReleaseFn(request.keys));
progressed = true;
break;
}
}
}
/**
* Acquire a slot for a provider/model/account tuple.
* Returns an idempotent release function that is safe to call in finally blocks.
*/
export function acquire(
semaphoreKey: string,
key: string,
{
maxConcurrency = null,
timeoutMs = DEFAULT_TIMEOUT_MS,
@@ -192,146 +210,118 @@ export function acquire(
maxQueueSize = DEFAULT_MAX_QUEUE_SIZE,
}: AcquireAccountSemaphoreOptions = {}
): Promise<() => void> {
if (isBypassed(maxConcurrency)) {
return Promise.resolve(createNoopReleaseFn());
return acquireMany([{ key, maxConcurrency }], { timeoutMs, signal, maxQueueSize });
}
/**
* Acquire all enabled requirements as one FIFO reservation.
*
* Waiting never increments any gate, preventing a saturated child gate from
* holding capacity in a parent gate.
*/
export function acquireMany(
requirements: SemaphoreRequirement[],
{
timeoutMs = DEFAULT_TIMEOUT_MS,
signal = null,
maxQueueSize = DEFAULT_MAX_QUEUE_SIZE,
}: AcquireManyOptions = {}
): Promise<() => void> {
const enabled = new Map<string, number>();
for (const requirement of requirements) {
if (isBypassed(requirement.maxConcurrency)) continue;
const limit = Math.trunc(requirement.maxConcurrency as number);
enabled.set(requirement.key, Math.min(enabled.get(requirement.key) ?? limit, limit));
}
if (enabled.size === 0) return Promise.resolve(createNoopReleaseFn());
if (signal?.aborted) return Promise.reject(makeAbortError(signal));
const keys = [...enabled.keys()].sort();
for (const key of keys) {
const gate = ensureGate(key, enabled.get(key)!);
clearCleanupTimer(gate);
if (maxQueueSize > 0 && gate.queue.length >= maxQueueSize) {
return Promise.reject(
createSemaphoreError(
"SEMAPHORE_QUEUE_FULL",
`Semaphore queue full (${maxQueueSize}) for ${key}`
)
);
}
}
if (signal?.aborted) {
return Promise.reject(makeAbortError(signal));
}
// isBypassed() above already excluded null/<=0 — ensureGate requires a plain
// number, but a boolean-returning helper isn't a type predicate TS can narrow on.
const gate = ensureGate(semaphoreKey, maxConcurrency as number);
clearCleanupTimer(gate);
if (gate.running < gate.maxConcurrency && !isBlocked(gate)) {
gate.running++;
return Promise.resolve(createReleaseFn(semaphoreKey));
}
if (gate.queue.length >= maxQueueSize) {
const err = new Error(`Semaphore queue full (${maxQueueSize}) for ${semaphoreKey}`) as Error & {
code: string;
};
err.code = "SEMAPHORE_QUEUE_FULL";
return Promise.reject(err);
if (
keys.every((key) => {
const gate = gates.get(key)!;
return gate.queue.length === 0 && gate.running < gate.maxConcurrency && !isBlocked(gate);
})
) {
for (const key of keys) gates.get(key)!.running++;
return Promise.resolve(createCompositeReleaseFn(keys));
}
return new Promise((resolve, reject) => {
let abortListener: (() => void) | null = null;
const cleanup = () => {
if (abortListener && signal) {
signal.removeEventListener("abort", abortListener);
}
const request: AcquireRequest = {
keys,
resolve,
reject,
timer: null,
signal,
abortListener: null,
settled: false,
};
const timer = setTimeout(() => {
cleanup();
const nextGate = gates.get(semaphoreKey);
if (!nextGate) {
reject(createSemaphoreTimeoutError(semaphoreKey, timeoutMs));
return;
}
const queueIndex = nextGate.queue.findIndex((item) => item.timer === timer);
if (queueIndex !== -1) {
nextGate.queue.splice(queueIndex, 1);
}
if (nextGate.running === 0 && nextGate.queue.length === 0) {
scheduleCleanup(semaphoreKey);
}
reject(createSemaphoreTimeoutError(semaphoreKey, timeoutMs));
request.timer = setTimeout(() => {
if (request.settled) return;
request.settled = true;
removeRequest(request);
reject(
createSemaphoreError(
"SEMAPHORE_TIMEOUT",
`Semaphore timeout after ${timeoutMs}ms for ${keys.join(",")}`
)
);
drainQueues();
}, timeoutMs);
timer.unref?.();
const queueItem: QueuedAcquire = {
resolve: (release) => {
cleanup();
resolve(release);
},
reject: (error) => {
cleanup();
reject(error);
},
timer,
};
gate.queue.push(queueItem);
request.timer.unref?.();
if (signal) {
abortListener = () => {
cleanup();
clearTimeout(timer);
const nextGate = gates.get(semaphoreKey);
if (!nextGate) {
reject(makeAbortError(signal));
return;
}
const queueIndex = nextGate.queue.findIndex((item) => item.timer === timer);
if (queueIndex !== -1) {
nextGate.queue.splice(queueIndex, 1);
}
if (nextGate.running === 0 && nextGate.queue.length === 0) {
scheduleCleanup(semaphoreKey);
}
request.abortListener = () => {
if (request.settled) return;
request.settled = true;
removeRequest(request);
reject(makeAbortError(signal));
drainQueues();
};
if (signal.aborted) {
abortListener();
} else {
signal.addEventListener("abort", abortListener);
}
signal.addEventListener("abort", request.abortListener, { once: true });
}
queuedRequests.add(request);
for (const key of keys) gates.get(key)!.queue.push({ request });
drainQueues();
});
}
/**
* Temporarily block new acquisitions for a key while allowing in-flight requests to finish.
*/
export function markBlocked(semaphoreKey: string, cooldownMs: number): void {
const safeCooldownMs = Number.isFinite(cooldownMs) && cooldownMs > 0 ? cooldownMs : 0;
if (safeCooldownMs <= 0) {
const gate = gates.get(semaphoreKey);
if (!gate) return;
gate.blockedUntil = null;
drainQueue(semaphoreKey);
return;
}
const gate = gates.get(semaphoreKey) ?? ensureGate(semaphoreKey, 1);
export function markBlocked(key: string, until: Date | string | number): void {
const untilMs =
until instanceof Date
? until.getTime()
: typeof until === "number"
? Date.now() + Math.max(0, until)
: new Date(until).getTime();
if (!Number.isFinite(untilMs) || untilMs <= Date.now()) return;
const gate = ensureGate(key, gates.get(key)?.maxConcurrency ?? 1);
clearCleanupTimer(gate);
gate.blockedUntil = Date.now() + safeCooldownMs;
gate.blockedUntil = untilMs;
}
const timer = setTimeout(() => {
const nextGate = gates.get(semaphoreKey);
if (!nextGate) return;
if (nextGate.blockedUntil && Date.now() >= nextGate.blockedUntil) {
nextGate.blockedUntil = null;
drainQueue(semaphoreKey);
if (nextGate.running === 0 && nextGate.queue.length === 0) {
scheduleCleanup(semaphoreKey);
}
}
}, safeCooldownMs + 50);
timer.unref?.();
export function unblock(key: string): void {
const gate = gates.get(key);
if (!gate) return;
gate.blockedUntil = null;
drainQueues();
cleanupGateIfIdle(key);
}
/**
* Return the current in-memory semaphore snapshot.
*/
export function getStats(): Record<string, AccountSemaphoreStatsEntry> {
const stats: Record<string, AccountSemaphoreStatsEntry> = {};
for (const [key, gate] of gates) {
stats[key] = {
running: gate.running,
@@ -340,48 +330,50 @@ export function getStats(): Record<string, AccountSemaphoreStatsEntry> {
blockedUntil: gate.blockedUntil ? new Date(gate.blockedUntil).toISOString() : null,
};
}
return stats;
}
/**
* Check if an account semaphore key is currently at or over its max concurrency limit.
* Returns true if running >= maxConcurrency or blocked.
*/
export function isAccountSemaphoreFull(
provider: string,
accountKey: string,
maxConcurrency?: number | null
): boolean {
if (isBypassed(maxConcurrency)) return false;
const key = buildAccountSemaphoreKey({ provider, accountKey });
const gate = gates.get(key);
const gate = gates.get(buildAccountSemaphoreKey({ provider, accountKey }));
if (!gate) return false;
const effectiveCap = maxConcurrency ?? gate.maxConcurrency;
if (isBypassed(effectiveCap)) return false;
return gate.running >= effectiveCap || isBlocked(gate);
return !isBypassed(effectiveCap) && (gate.running >= effectiveCap || isBlocked(gate));
}
/**
* Reset a single key and reject queued waiters.
*/
export function reset(semaphoreKey: string): void {
const gate = gates.get(semaphoreKey);
export function reset(key: string): void {
const gate = gates.get(key);
if (!gate) return;
clearCleanupTimer(gate);
for (const entry of gate.queue) {
clearTimeout(entry.timer);
entry.reject(new Error("Semaphore reset"));
const error = createSemaphoreError("SEMAPHORE_RESET", `Semaphore reset for ${key}`);
const rejections: AcquireRequest[] = [];
for (const queued of [...gate.queue]) {
const request = queued.request;
if (request.settled) continue;
request.settled = true;
removeRequest(request);
rejections.push(request);
}
gates.delete(semaphoreKey);
gates.delete(key);
for (const request of rejections) request.reject(error);
drainQueues();
}
/**
* Reset all keys and reject queued waiters.
*/
export function resetAll(): void {
for (const key of gates.keys()) {
reset(key);
const error = createSemaphoreError("SEMAPHORE_RESET", "Semaphore reset");
const rejections: AcquireRequest[] = [];
for (const request of [...queuedRequests]) {
if (request.settled) continue;
request.settled = true;
removeRequest(request);
rejections.push(request);
}
for (const gate of gates.values()) clearCleanupTimer(gate);
gates.clear();
queuedRequests.clear();
for (const request of rejections) request.reject(error);
}

View File

@@ -50,6 +50,7 @@
*/
import {
FREE_MODEL_BUDGETS,
grantsFreeAccess,
type FreeModelBudget,
} from "@omniroute/open-sse/config/freeModelCatalog.ts";
import { SYNTHETIC_NOAUTH_CONNECTION_ID } from "./resilienceCandidateFilter";
@@ -184,7 +185,7 @@ export function evaluateCandidateConnections(
// entries today, so it will correctly exclude).
if (isGenuineNoAuthCandidate) return [SYNTHETIC_NOAUTH_CONNECTION_ID];
}
if (budgetEntry.freeType === "discontinued") return [];
if (!grantsFreeAccess(budgetEntry.freeType)) return [];
if (isGenuineNoAuthCandidate) return []; // no-auth path but a non-keyless catalog entry: contradictory metadata, fail closed
// Every remaining freeType (recurring-*, one-time-initial, a keyless entry

View File

@@ -261,7 +261,7 @@ function getWindowsMapQuotaWindow(
);
}
function resolveQuotaWindowByName(
export function resolveQuotaWindowByName(
quota: unknown,
windowName: ResetWindowName
): QuotaWindowSnapshot | null {
@@ -321,8 +321,8 @@ export function scoreResetAwareQuota(
if (quota.limitReached === true) return { score: -Infinity };
const overallPercentUsed = clamp01(finiteNumberOrNull(quota.percentUsed) ?? 0.5);
const sessionWindow = getQuotaWindow(quota, "window5h");
const weeklyWindow = getQuotaWindow(quota, "window7d") || getQuotaWindow(quota, "windowWeekly");
const sessionWindow = resolveQuotaWindowByName(quota, "session");
const weeklyWindow = resolveQuotaWindowByName(quota, "weekly");
const sessionRemaining = clamp01(1 - (sessionWindow?.percentUsed ?? overallPercentUsed));
const weeklyRemaining = clamp01(1 - (weeklyWindow?.percentUsed ?? overallPercentUsed));
const sessionScore = scoreQuotaWindow(

View File

@@ -16,9 +16,10 @@ export function createExecutorModelClient(
credentials: ProviderCredentials,
costPerKTokenOut?: number
): ModelClient {
const executor = getExecutor(provider);
return {
async complete(model: string, messages: ChatTurn[]): Promise<ModelCallResult> {
// #11220: getExecutor is async (lazy registry) — resolve per call.
const executor = await getExecutor(provider);
const body = { model, messages, stream: false };
const input: ExecuteInput = {
model,

View File

@@ -150,16 +150,65 @@ export function convertUsageToQuotaInfo(usage: unknown): QuotaInfo | null {
if (Object.keys(windows).length === 0) return null;
const normalized = normalizeQuotaWindows(windows);
Object.assign(windows, normalized);
return {
used: 0,
total: 0,
percentUsed: worstPercent,
resetAt: worstResetAt,
windows,
...normalized,
limitReached: worstPercent >= 1 - 1e-9,
};
}
/**
* Map provider-native window keys to canonical structural windows so that
* reset-aware / reset-window scoring works without knowing every provider's
* naming convention.
*
* - Claude: "session (5h)" → window5h, "weekly (7d)" → window7d
* - Antigravity: worst per-model quota → window5h; worst *_weekly quota → window7d
*/
function normalizeQuotaWindows(
windows: Record<string, { percentUsed: number; resetAt: string | null }>
): Record<string, { percentUsed: number; resetAt: string | null }> {
const normalized: Record<string, { percentUsed: number; resetAt: string | null }> = {};
// Claude-style explicit time windows.
if (windows["session (5h)"] && !normalized.window5h) {
normalized.window5h = windows["session (5h)"];
}
if (windows["weekly (7d)"] && !normalized.window7d) {
normalized.window7d = windows["weekly (7d)"];
}
// Antigravity-style per-model 5h windows: pick the worst (most used) model quota.
const modelWindows = Object.entries(windows).filter(
([key]) =>
key !== "credits" &&
!key.endsWith("_weekly") &&
!key.startsWith("window") &&
!key.includes("(5h)") &&
!key.includes("(7d)")
);
if (modelWindows.length > 0 && !normalized.window5h) {
const worst = modelWindows.reduce((a, b) => (a[1].percentUsed > b[1].percentUsed ? a : b));
normalized.window5h = worst[1];
}
// Antigravity-style weekly family buckets: pick the worst *_weekly quota.
const weeklyWindows = Object.entries(windows).filter(([key]) => key.endsWith("_weekly"));
if (weeklyWindows.length > 0 && !normalized.window7d) {
const worst = weeklyWindows.reduce((a, b) => (a[1].percentUsed > b[1].percentUsed ? a : b));
normalized.window7d = worst[1];
}
return normalized;
}
/**
* Fetch quota for a connection by delegating to the appropriate
* provider-specific usage fetcher and reshaping its output into the

View File

@@ -48,6 +48,16 @@ export interface QuotaInfo {
* (e.g. "session", "weekly", "monthly").
*/
windows?: Record<string, QuotaWindowInfo>;
/**
* Structural, canonical window snapshots used by reset-aware / reset-window
* scoring. Providers that expose time-based windows (5h, weekly, monthly)
* populate these in addition to the provider-native `windows` map so the
* scorer does not need to know every provider's key naming convention.
*/
window5h?: QuotaWindowInfo;
window7d?: QuotaWindowInfo;
windowWeekly?: QuotaWindowInfo;
windowMonthly?: QuotaWindowInfo;
/** True when the upstream usage endpoint explicitly reports exhausted quota. */
limitReached?: boolean;
}

View File

@@ -96,13 +96,6 @@ const ARK_CONSOLE_URL =
/** Cookie names required for a valid console session (mirrors tokenExtractionConfig) */
const REQUIRED_COOKIES = ["digest", "AccountID", "csrfToken", "userInfo"] as const;
/** Exact-domain match for session cookies — substring checks would also accept
* look-alike hosts (e.g. `volcengine.com.evil.test`). Playwright may report the
* domain with or without a leading dot. */
function isVolcengineCookieDomain(domain: string): boolean {
return domain === "volcengine.com" || domain.endsWith(".volcengine.com");
}
const DEFAULT_SESSION_TIMEOUT = 300_000;
const SUBMIT_COOKIE_TIMEOUT = 90_000;
const CAPTURE_POLL_INTERVAL = 1_000;
@@ -625,7 +618,7 @@ export class VolcengineConsoleAutoLoginService {
for (const cookie of cookies as Array<{ name: string; domain: string; value: string }>) {
if (
REQUIRED_COOKIES.includes(cookie.name as (typeof REQUIRED_COOKIES)[number]) &&
isVolcengineCookieDomain(cookie.domain)
cookie.domain.includes("volcengine.com")
) {
credentials[cookie.name] = cookie.value;
}
@@ -770,7 +763,7 @@ export class VolcengineConsoleAutoLoginService {
domain: string;
}>;
const present = REQUIRED_COOKIES.filter((name) =>
cookies.some((c) => c.name === name && isVolcengineCookieDomain(c.domain))
cookies.some((c) => c.name === name && c.domain.includes("volcengine.com"))
);
parts.push(
`cookies=[${present.join(",") || "none of digest/AccountID/csrfToken/userInfo"}]`

2436
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -261,7 +261,7 @@
"alibaba:sync-allowlist": "node --import tsx/esm scripts/ops/sync-alibaba-allowlist.mjs"
},
"dependencies": {
"@aws-sdk/client-bedrock-runtime": "^3.1112.0",
"@aws-sdk/client-bedrock-runtime": "^3.1116.0",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
@@ -280,29 +280,29 @@
"commander": "^15.0.0",
"cron-parser": "^5.10.0",
"csv-stringify": "^6.8.3",
"dompurify": "^3.4.13",
"dompurify": "^3.4.14",
"express": "^5.2.1",
"fetch-socks": "^1.3.3",
"fflate": "^0.8.3",
"fumadocs-core": "^16.14.4",
"fumadocs-ui": "^16.14.4",
"fumadocs-core": "^16.15.1",
"fumadocs-ui": "^16.15.1",
"http-proxy-middleware": "^4.0.0",
"https-proxy-agent": "^9.0.0",
"ink": "^7.0.3",
"ink-spinner": "^5.0.0",
"ink-text-input": "^6.0.0",
"ioredis": "^5.10.1",
"jose": "^6.2.9",
"jose": "^6.2.10",
"js-yaml": "^5.3.0",
"jsonc-parser": "^3.3.1",
"lowdb": "^7.0.1",
"lucide-react": "^1.21.0",
"marked": "^18.0.9",
"lucide-react": "^1.33.0",
"marked": "^18.0.10",
"marked-terminal": "^7.3.0",
"material-symbols": "^0.46.0",
"mermaid": "^11.15.0",
"mermaid": "^11.17.0",
"monaco-editor": "^0.56.0",
"next": "16.3.1",
"next": "16.3.2",
"next-intl": "^4.13.7",
"next-themes": "^0.4.6",
"node-machine-id": "^1.1.12",
@@ -332,7 +332,7 @@
"turndown-plugin-gfm": "1.0.2",
"undici": "^8.10.0",
"update-notifier": "^7.3.1",
"uuid": "^14.0.0",
"uuid": "^14.0.2",
"ws": "^8.21.3",
"xxhash-wasm": "^1.1.0",
"yazl": "^3.3.1",
@@ -348,11 +348,12 @@
"onnxruntime-node": "1.24.3",
"sqlite-vec": "^0.1.9",
"tls-client-node": "^0.2.0",
"wreq-js": "^3.0.0"
"wreq-js": "^3.1.0"
},
"devDependencies": {
"@axe-core/playwright": "^4.13.0",
"@cyclonedx/cyclonedx-npm": "6.0.1",
"@eslint/compat": "^2.1.0",
"@playwright/test": "^1.62.1",
"@size-limit/file": "^13.0.3",
"@stryker-mutator/core": "^10.0.0",
@@ -363,24 +364,25 @@
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.6",
"@types/better-sqlite3": "^9.6.0",
"@types/bun": "latest",
"@types/bun": "1.4.0",
"@types/node": "^26.2.0",
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.4",
"@types/safe-regex": "^1.1.6",
"@types/ws": "^8.18.0",
"@vitejs/plugin-react": "^6.0.5",
"bun": "1.3.14",
"@vitejs/plugin-react": "^6.1.0",
"bun": "1.4.0",
"c8": "^12.0.0",
"concurrently": "^10.0.5",
"cross-env": "^10.1.0",
"ctrf": "^0.3.0",
"dpdm": "^4.3.0",
"eslint": "^9.39.4",
"eslint-config-next": "16.3.1",
"eslint": "^10.9.0",
"eslint-config-next": "16.3.2",
"eslint-plugin-sonarjs": "^4.1.0",
"espree": "^11.2.0",
"fast-check": "^4.8.0",
"fumadocs-mdx": "^15.2.3",
"fumadocs-mdx": "^15.3.1",
"glob": "^13.0.6",
"httpyac": "^6.16.7",
"husky": "^9.1.7",
@@ -392,7 +394,7 @@
"lint-staged": "^17.3.0",
"lockfile-lint": "^5.0.1",
"node-loader": "^2.1.0",
"opencode-ai": "1.18.18",
"opencode-ai": "1.18.21",
"playwright-ctrf-json-reporter": "^0.0.29",
"prettier": "^3.9.6",
"promptfoo": "^0.122.0",
@@ -401,7 +403,7 @@
"type-coverage": "^2.30.1",
"typescript": "^6.0.3",
"typescript-eslint": "^8.67.0",
"vitest": "^4.1.7",
"vitest": "^4.1.11",
"wait-on": "^9.1.0",
"wtfnode": "^0.10.1"
},
@@ -435,12 +437,13 @@
},
"overrides": {
"onnxruntime-node": "1.24.3",
"eslint-plugin-react-hooks": "7.0.1",
"fast-xml-parser": "^5.10.1",
"sharp": "^0.35.3",
"postcss": "^8.5.18",
"ip-address": "^10.3.1",
"qs": "^6.15.2",
"uuid": "^14.0.0",
"uuid": "^14.0.2",
"form-data": "^4.0.6",
"vite": "^8.0.16",
"protobufjs": "^7.6.5",
@@ -468,10 +471,6 @@
},
"socket.io-parser": "^4.2.7",
"tar": "^7.5.21",
"brace-expansion": "^5.0.9",
"minimatch": {
"brace-expansion": "^1.1.18"
},
"libxmljs2": {
"minimatch": {
"brace-expansion": "^2.1.4"
@@ -496,7 +495,7 @@
},
"nanoid": "^3.3.17",
"monaco-editor": {
"dompurify": "^3.4.13"
"dompurify": "^3.4.14"
}
}
}

View File

@@ -0,0 +1,34 @@
import { cpSync, existsSync, readdirSync, rmSync } from "node:fs";
import { join } from "node:path";
// electron-builder >=26 injects an "!**/node_modules/**" ignore into every
// extraResources/extraFiles pattern list (app-builder-lib/out/fileMatcher.js),
// and that ignore cannot be overridden by any later positive filter pattern —
// verified empirically with a minimal fixture on 26.15.3. The standalone
// server resolves better-sqlite3 (and other runtime deps) from the *primary*
// node_modules at resources/app/node_modules (see
// prepare-electron-standalone.mjs: "Verify better-sqlite3 Node-API prebuilds in
// the primary node_modules"), so without this hook the packaged desktop app silently loses its native
// SQLite driver and falls back to sql.js — the exact regression guarded by
// issue #7592's cold-restart smoke check.
export default async function afterPack(context) {
const stagingNodeModules = join(
context.packager.projectDir,
"..",
".build",
"electron-standalone",
"node_modules"
);
const destNodeModules = join(context.appOutDir, "resources", "app", "node_modules");
if (!existsSync(stagingNodeModules)) {
console.warn(`[afterpack] no staged node_modules at ${stagingNodeModules} — skipping restore`);
return;
}
rmSync(destNodeModules, { recursive: true, force: true });
cpSync(stagingNodeModules, destNodeModules, { recursive: true });
console.log(
`[afterpack] restored ${readdirSync(destNodeModules).length} runtime module(s) into resources/app/node_modules`
);
}

View File

@@ -89,16 +89,20 @@ function moveTree(src, dest) {
return { removedFiles: files, removedBytes: bytes };
}
function tarPack(packOutDir, tarballPath) {
export function tarPack(packOutDir, tarballPath) {
// bsdtar ships with macOS, Linux images, and Windows runners (System32\tar.exe).
// GNU tar (common in Git-for-Windows environments) treats `C:\...` in `-f` as a
// remote rsh target ("Cannot connect to C:"), so always pass a bare filename
// and point cwd at the tarball directory instead.
const result = spawnSync(
process.platform === "win32" ? "tar.exe" : "tar",
["-czf", tarballPath, "-C", packOutDir, "node_modules"],
{ stdio: "pipe" }
["-czf", path.basename(tarballPath), "-C", packOutDir, "node_modules"],
{ stdio: "pipe", cwd: path.dirname(tarballPath) }
);
if (result.status !== 0) {
throw new Error(
`optional-pack tar failed for ${path.basename(tarballPath)} (exit ${result.status})`
`optional-pack tar failed for ${path.basename(tarballPath)} (exit ${result.status})` +
`: ${(result.stderr || result.stdout || "").toString().slice(-600)}`
);
}
}

View File

@@ -360,7 +360,7 @@ function isInsideDir(parentDir, candidateDir) {
return candidate === parent || candidate.startsWith(parent + sep);
}
async function ensureSmokeEnvDirs(smokeEnv, dataDir) {
export async function ensureSmokeEnvDirs(smokeEnv, dataDir) {
const dirNames = [
"DATA_DIR",
"HOME",
@@ -388,6 +388,16 @@ async function ensureSmokeEnvDirs(smokeEnv, dataDir) {
dirs.push(join(smokeEnv.APPDATA, subdir));
}
}
// Electron resolves the Roaming profile from %USERPROFILE%\AppData\Roaming
// (USERPROFILE takes precedence over the APPDATA env var) and the path
// service throws — rather than creates — when that directory is missing,
// which makes requestSingleInstanceLock() return false and the app exit(0)
// before app.whenReady(). Pre-create the derived tree as well.
if (platform() === "win32" && smokeEnv.USERPROFILE) {
for (const subdir of ["omniroute-desktop", "OmniRoute", "omniroute"]) {
dirs.push(join(smokeEnv.USERPROFILE, "AppData", "Roaming", subdir));
}
}
await Promise.all(dirs.map((dir) => mkdir(dir, { recursive: true })));
}
@@ -506,7 +516,14 @@ async function waitForReady({ logs, smokeUrl, timeoutMs, settleMs, exitState })
* by the single-launch path and the cold-restart (two-launch) path so both
* exercise identical spawn/readiness/shutdown behavior.
*/
async function launchAndCollectLogs({ appExecutable, smokeUrl, dataDir, timeoutMs, settleMs, streamLogs }) {
async function launchAndCollectLogs({
appExecutable,
smokeUrl,
dataDir,
timeoutMs,
settleMs,
streamLogs,
}) {
const smokeEnv = buildSmokeEnv({ dataDir });
await assertPortIsFree(smokeUrl);
await ensureSmokeEnvDirs(smokeEnv, dataDir);
@@ -568,7 +585,14 @@ async function main() {
!process.env.ELECTRON_SMOKE_DATA_DIR && process.env.ELECTRON_SMOKE_KEEP_DATA !== "1";
try {
await launchAndCollectLogs({ appExecutable, smokeUrl, dataDir, timeoutMs, settleMs, streamLogs });
await launchAndCollectLogs({
appExecutable,
smokeUrl,
dataDir,
timeoutMs,
settleMs,
streamLogs,
});
if (!coldRestart) return;

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