From f0e34a717f3ab1d1fd563f37e4b4cf332224bcea Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza Date: Sat, 11 Jul 2026 04:36:35 -0300 Subject: [PATCH] fix(db): register interceptionRules in localDb re-export layer (db-rules gate) --- CHANGELOG.md | 108 ++++++++++++++++++++++++++++++--------------- src/lib/localDb.ts | 2 +- 2 files changed, 73 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51eb2fa7b2..2028f645f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,8 @@ _Living section — bullets land here as PRs merge into `release/v3.8.47` (paral ### ✨ New Features +- **feat(combo):** `auto/*` combos gain a strict budget-cap fallback policy — `X-OmniRoute-Budget-Fallback: strict` (or the persisted `config.budgetFallback: "strict"`) makes an over-budget request fail fast with `HTTP 402` instead of the previous silent fallback to the globally cheapest candidate, which could still exceed the cap. The default (`cheapest`) preserves existing behavior. Builds on the existing `X-OmniRoute-Budget`/`X-OmniRoute-Mode` per-request controls (#6023/#6024/#6025), consolidated into `resolveRequestAutoControls()`. Regression guard: `tests/unit/auto-combo-budget-fallback-3470.test.ts`. (#3470) - **Provider/model param filters**: config-driven parameter denylist/allowlist per provider/model with auto-learn from upstream 400s (#6649 — thanks @ThongAccount, closes #6625) -- **Per-model web-search interception rule (Phase 1/2)**: a new `interceptSearch` rule, resolvable per provider or per model (`src/lib/db/interceptionRules.ts`, `key_value` namespace `interception_rules`), now overrides the existing native web-search bypass defaults (Codex/Gemini/Claude→Claude passthrough) — set `interceptSearch:true` to force a model's provider-native web-search tool call through OmniRoute's own `/v1/search` fallback even when it would otherwise be forwarded natively, or `interceptSearch:false` to force native passthrough for a model that would otherwise be converted. Per-model rule takes precedence over the provider-level rule, which takes precedence over the existing defaults when unset. Wired at the existing `prepareWebSearchFallbackBody()` call site in `chatCore.ts`. Web-fetch interception + the dashboard UI toggle are tracked as follow-up phases. Regression guard: `tests/unit/interception-rules.test.ts`, extended `tests/unit/web-search-fallback-format.test.ts` (#3384 — thanks @thomasmaerz) - **Per-combo reasoning token buffer toggle**: the combo builder now exposes an explicit checkbox for the `#3587` reasoning-model `max_tokens` buffer, defaulting to the existing enabled behavior, so a combo can opt out without hand-editing raw JSON config (#6702 — thanks @xz-dev) - **feat(dashboard):** 9router-parity **Routing Strategy** settings card on Settings → Routing, plus a per-provider account-routing override on the provider detail page ([#6678](https://github.com/diegosouzapw/OmniRoute/pull/6678)) — surfaces the existing account round-robin / sticky-limit knobs and adds a new combo-level sticky round-robin (`comboStickyRoundRobinLimit`, resolved via `resolveComboStickyRoundRobinLimit()` — per-combo → global combo sticky → account sticky cascade) so combo targets can batch calls per target the same way account fallback already does. A new `providerStrategies` setting (Zod-validated map, `src/shared/validation/settingsSchemas.ts`) lets a specific provider override the global `fallbackStrategy`/`stickyRoundRobinLimit` without touching the account-wide default, wired into `getProviderCredentials()` (`src/sse/services/auth.ts`) ahead of the global fallback. Regression guard: `tests/unit/combo-rr-sticky-9router.test.ts`, `tests/unit/settings-ui-layout-static.test.ts`. (thanks @SeaXen) - **feat(icons):** provider logos now resolve local SVG assets first for faster rendering, with a 5-tier fallback chain — local SVG → `@lobehub/icons` React components → `thesvg.org` CDN (external SVG for unknown providers) → local PNG → generic AI icon — replacing the previous LobeHub-first order. Adds dozens of first-party provider SVGs and migrates several bitmap logos (continue/copilot/cursor/deepgram/heroku/openclaw/ovhcloud) from PNG to SVG. Regression guard: `tests/unit/ui/ProviderIcon-icon-url.test.tsx`. ([#6317](https://github.com/diegosouzapw/OmniRoute/pull/6317) — thanks @hamsa0x7) @@ -23,14 +23,17 @@ _Living section — bullets land here as PRs merge into `release/v3.8.47` (paral - **Kiro long-lived API key auth**: new `/api/oauth/kiro/api-key` route + `KiroService.validateApiKey` let a Kiro account be linked with a long-lived AWS CodeWhisperer/Kiro API key instead of the interactive OAuth device flow, with live per-account model discovery (`ListAvailableModels`, 5-minute cache) layered over the existing static registry fallback (#6587 — thanks @strangersp) - **Chaos Mode**: multi-model parallel/collaborative task execution — dispatches a task to every active provider connection at once (parallel) or chains outputs sequentially so each model builds on the previous one's answer (collaborative), configurable via Dashboard → Chaos Mode (`GET`/`PUT`/`DELETE /api/chaos/config`) and gated per-API-key via a new `chaosModeEnabled` permission (opt-in — disabled by default globally and per key). `POST /api/chaos/run` (dashboard session) and `POST /api/skills/collect/chaos` (external Bearer-token) delegate to a shared `executeChaosRun()` engine (`src/lib/chaos/chaosExecutor.ts`) that dispatches in-process via the established synthetic-Request/route-handler pattern (no network hop, no hardcoded port), with a concurrency cap (max 10 parallel), configurable `max_tokens` (256–128k), a clear error when `stream` is requested, and collaborative-chain info (provider order + input size). Fixes external Bearer-auth bypass and stale config-cache leakage. Regression guard: `tests/unit/chaos-config.test.ts`, `tests/unit/chaos-executor.test.ts`, `tests/unit/chaos-api-routes.test.ts`. ([#6728](https://github.com/diegosouzapw/OmniRoute/pull/6728) — thanks @Moseyuh333) - **feat(cli):** 2 new CLI tool integrations on Dashboard → CLI Tools — **omp** (Oh My Pi) and **letta** — each with binary detection, config apply/reset, and a settings card following the existing tool-card pattern. Both settings routes shell out to `which omp`/`which letta` to detect the local install, so they're loopback-gated (`LOCAL_ONLY_API_PREFIXES`, Hard Rules #15/#17) in addition to the shared `requireCliToolsAuth()` management-auth guard every cli-tools route requires, and route errors through `sanitizeErrorMessage()`; `src/lib/db/omp.ts` isolates the `omp` CLI's own local SQLite reads behind parameterized queries. (Note: the original PR also proposed **pi**, **codewhale**, and **jcode** integrations — those three had already shipped via a separate PR by the time this one was reconciled, so only omp+letta landed here.) Regression guard: `tests/unit/db/omp.test.ts`, `tests/unit/cli-tools-auth-hardening.test.ts`, `tests/integration/cli-settings-omp.test.ts`, `tests/integration/cli-settings-letta.test.ts`. ([#6318](https://github.com/diegosouzapw/OmniRoute/pull/6318) — thanks @hamsa0x7) +- **feat(providers):** custom models now support a manual **Context Window Override** so an operator can correct a provider's misreported context length (e.g. reports 1M when the real limit is 128K) instead of the model silently getting dropped from combo routing once the wrong value lands in the catalog ([#4125](https://github.com/diegosouzapw/OmniRoute/issues/4125) — thanks @rucciva). Reuses the existing Feature-5004 `model_context_overrides` table (`source: "manual"`) — already the priority-0 source `getModelContextLimit()` (the function combo's context-window filter calls) reads ahead of the models.dev/registry/static catalog — so no new resolver logic was needed, only the missing write path: `PUT /api/provider-models` now accepts an optional `contextWindowOverride` (number to set, `null` to clear), `GET` surfaces the current value back on each custom-model row, and the provider detail page's custom-model edit form gained a Context Window Override field + badge. Regression guard: `tests/unit/provider-models-context-window-override-4125.test.ts`. - **fix(providers):** register OpenRouter as a rerank provider so `openrouter/cohere/rerank-*` models resolve instead of erroring `Invalid rerank model` (#6574 — thanks @rafpigna) - **fix(api):** `HEAD` requests no longer hang until client timeout on any route — valid, unknown, authed, or unauthed ([#6400](https://github.com/diegosouzapw/OmniRoute/issues/6400)), broader follow-up to the route-specific #6517 (`/v1/models`). Root cause: Next.js 16's App Router _route-handler_ pipeline (`next/dist/server/send-response.js`) correctly skips piping a `Response` body for `HEAD`, but its _page_-rendering pipeline (`next/dist/server/pipe-readable.js` → `pipeToNodeResponse`, used for every app-router page/layout render — including the `not-found` boundary any unmatched path falls through to) has no such check and always streams the full rendered body regardless of method; combined with Node's default keep-alive framing this left some clients unsure whether the (implicitly bodyless) `HEAD` response had actually finished. A new `scripts/dev/head-response-guard.cjs`, wired into both the dev/start custom server (`scripts/dev/run-next.mjs`) and the packaged standalone server (`scripts/dev/standalone-server-ws.mjs`) at the same tier as the existing `http-method-guard.cjs`/`peer-stamp.mjs` wrappers, discards any body bytes written for a `HEAD` request and forces `Connection: close` once `.end()` is called — independent of route existence or auth state, satisfying RFC 9110 §9.3.2. Regression guard: `tests/unit/head-request-closes-6400.test.ts`. +- **feat(dashboard):** Provider Quota page (`Dashboard → Quota`) fills horizontal whitespace before stacking vertically ([#3520](https://github.com/diegosouzapw/OmniRoute/issues/3520)) — `QuotaCardGrid` previously stacked every provider group in a single vertical `flex flex-col`, and each group's own card grid didn't go multi-column until `md` (`grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4`). Provider groups now flow into a 2-column CSS multi-column layout on very wide (`2xl`) screens instead of an unconditional vertical stack, and each group's card grid starts at 2 columns immediately (`grid-cols-2 md:grid-cols-3 xl:grid-cols-4`), reaching higher density sooner on narrower-but-not-mobile viewports. Regression guard: `tests/unit/quota-card-grid-horizontal-layout.test.ts` (thanks @gdevenyi). ### 🐛 Bug Fixes +- **fix(cli):** the dashboard's Claude Code CLI card could report "Not detected"/"Not installed" even when Claude Code was genuinely installed and previously used ([#6701](https://github.com/diegosouzapw/OmniRoute/issues/6701)) — `getCliRuntimeStatus()` (`src/shared/services/cliRuntime.ts`) determined `installed` purely from binary resolution (known install paths + a `where`/`which` PATH search), with no fallback when that lookup fails for reasons unrelated to whether the CLI is actually installed (stale PATH inherited by a long-running/background process, the binary having moved, an install method not yet catalogued, etc.) — even though `~/.claude/settings.json` on disk proves the tool was installed and used before. Upstream 9router's equivalent route already has this exact fallback. A new `withSettingsFallback()` (`src/shared/services/cliInstallFallback.ts`) restores 9router parity: when the binary lookup's own reason is `"not_found"` (never for deliberate security rejections like unsafe/relative env overrides or symlink escapes) and the tool's settings file exists on disk, `installed` now reports `true`. Regression guard: `tests/unit/repro-6701-claude-detect-fallback.test.ts`. - **fix(cli):** per-agent AgentBridge DNS toggle was broken for 8 of the 9 supported agents, and a failed MITM startup step could orphan the spawned proxy child — `addDNSEntry`/`removeDNSEntry` (`src/mitm/dns/dnsConfig.ts`) always resolved the legacy Antigravity default hosts regardless of which agent's toggle was flipped, so enabling DNS for Cursor/Codex/Claude Code/etc. silently added only `daily-cloudcode-pa.googleapis.com` while the DB recorded `dns_enabled=true` for the selected agent. Both functions now accept an optional `agentId` and resolve hosts via `ALL_TARGETS`; `POST /api/tools/agent-bridge/agents/[id]/dns` passes the route's `id` through and now returns 404 for an id that doesn't match a known target instead of silently falling back. Separately, `startMitmInternal()` (`src/mitm/manager.ts`) now wraps `generateCert()` (log + rethrow), the `provisionDnsEntries()` call, and the PID-file write in try/catch so a mid-startup failure can't orphan the already-spawned MITM child process. On Windows, `addDNSEntries`/`removeDNSEntries` also batch every missing/present entry into a single elevated PowerShell invocation instead of one UAC prompt per host line. Regression guard: `tests/unit/dns-config-generic.test.ts` (agent-specific resolution + batching), `tests/unit/agent-bridge-dns-route-validation.test.ts` (404 for unknown agent id). ([#6338](https://github.com/diegosouzapw/OmniRoute/pull/6338) — thanks @hamsa0x7) - **fix(guardrails):** Vision Bridge's individual-model auto-reroute (route an image-bearing request straight to a vision-capable model instead of describe-then-forward) could bypass a policy-restricted API key's model allowlist/budget ([#6640](https://github.com/diegosouzapw/OmniRoute/pull/6640)) — `VisionBridgeGuardrail.preCall()` (`src/lib/guardrails/visionBridge.ts`) swaps `body.model` to the best available vision-capable model, but that swap happens in the guardrail pipeline AFTER `chat.ts` already called `enforceApiKeyPolicy()` against the ORIGINAL model, so a key scoped to a narrow `allowedModels` list could still execute against an unvetted (and possibly costlier) vision model the reroute picked. `chat.ts` now re-validates any guardrail-driven model change against the same per-key allowlist (`isModelAllowedForKey`) before honoring it, falling back to the original already-approved model when the reroute target is not allowed. The reroute path also now honors an explicit `settings.visionBridgeModel` operator override (previously ignored, unlike the combo/describe path a few lines below it, which already respects it via `getVisionBridgeConfig`). Regression guard: `tests/unit/guardrails/visionBridge.test.ts` (22 tests). (thanks @herjarsa) -- **fix(auth):** an API key restricted via `allowedModels`/`allowedCombos` could bypass that restriction entirely over the Codex Responses-over-WebSocket bridge ([#6564](https://github.com/diegosouzapw/OmniRoute/issues/6564)) — `prepare()` in `src/app/api/internal/codex-responses-ws/route.ts` authenticated the WS bridge's API key (`authenticate()`/`authorizeWebSocketHandshake()`) and honored `allowedConnections`, but never called `enforceApiKeyPolicy()`, the same model/combo policy gate the HTTP `/v1/responses` path enforces via `handleChat()` — so a key scoped to e.g. `combo/model-1.0` could still reach a direct Codex model like `gpt-5.5` through this transport, as long as an eligible Codex OAuth connection existed. The bridge's WS auth token arrives via query params (`api_key`/`token`/`access_token`), not a normal `Authorization` header, so a new `enforceCodexWsApiKeyPolicy()` builds an equivalent `Request` carrying an explicit `Authorization: Bearer ` header and calls `enforceApiKeyPolicy()` against the CLIENT-requested model, before any Codex-specific model remapping or credential selection. Regression guard: `tests/unit/codex-ws-policy-enforcement-6564.test.ts` (a model-restricted key is rejected 403 before reaching credential selection; a combo-restricted key is rejected 403 requesting a disallowed combo; a key that DOES allow the requested model still proceeds past policy). +- **fix(auth):** an API key restricted via `allowedModels`/`allowedCombos` could bypass that restriction entirely over the Codex Responses-over-WebSocket bridge ([#6564](https://github.com/diegosouzapw/OmniRoute/issues/6564)) — `prepare()` in `src/app/api/internal/codex-responses-ws/route.ts` authenticated the WS bridge's API key (`authenticate()`/`authorizeWebSocketHandshake()`) and honored `allowedConnections`, but never called `enforceApiKeyPolicy()`, the same model/combo policy gate the HTTP `/v1/responses` path enforces via `handleChat()` — so a key scoped to e.g. `combo/model-1.0` could still reach a direct Codex model like `gpt-5.5` through this transport, as long as an eligible Codex OAuth connection existed. The bridge's WS auth token arrives via query params (`api_key`/`token`/`access_token`), not a normal `Authorization` header, so a new `enforceCodexWsApiKeyPolicy()` builds an equivalent `Request` carrying an explicit `Authorization: Bearer ` header and calls `enforceApiKeyPolicy()` against the CLIENT-requested model, before any Codex-specific model remapping or credential selection. Regression guard: `tests/unit/codex-ws-policy-enforcement-6564.test.ts` (a model-restricted key is rejected 403 before reaching credential selection; a combo-restricted key is rejected 403 requesting a disallowed combo; a key that DOES allow the requested model still proceeds past policy). (thanks @Squawk7777 for the report and an independent fix via #6565) - **fix(security):** loopback-gate `/api/middleware/*` so a leaked JWT over a tunnel can't install or trigger a middleware hook — middleware hooks compile + run arbitrary JS via `new vm.Script` on the request hot path (`src/lib/middleware/registry.ts`), the same RCE class as the already-gated `/api/plugins/*`; `/api/middleware/` is now in `LOCAL_ONLY_API_PREFIXES` so loopback enforcement runs unconditionally before any auth check (Hard Rules #15 + #17). Regression guard: `tests/unit/route-guard-middleware-local-only.test.ts`. ([#6541](https://github.com/diegosouzapw/OmniRoute/pull/6541)) — see PR. (thanks @developerjillur) - **fix(startup):** AgentBridge's MITM server no longer fails to start with `ROUTER_API_KEY is required` on a normal install ([#6403](https://github.com/diegosouzapw/OmniRoute/issues/6403)) — `POST /api/tools/agent-bridge/server` resolved the spawned MITM child's router key from only an explicit `apiKey` body field (never sent by the AgentBridge UI — the schema has no such field) and the `ROUTER_API_KEY` env var (unset by default), so `startMitm()` always received `""` and the child hard-exited, even though OmniRoute already had a usable API key in its own DB. A new `resolveRouterApiKey()` now falls back to `pickApiKeyForInternalUse()` (the same DB-backed selector the combo-health-check / cloud-sync internal probes use), resolving in order: explicit key → `ROUTER_API_KEY` env → an existing DB key. Regression guard: `tests/unit/agentbridge-mitm-router-key-6403.test.ts`. - **fix(providers):** deploying a Cloudflare relay Worker from Dashboard → System → Proxy pool → Cloudflare relay failed immediately with `Cloudflare Worker upload failed: Content-Type must be one of: application/javascript, text/javascript, multipart/form-data`, even with a valid token/account ([#6416](https://github.com/diegosouzapw/OmniRoute/issues/6416)) — the Worker-script upload built a native `FormData` and let `fetch` derive the multipart Content-Type automatically, but in production `globalThis.fetch` is patched with `node_modules/undici`'s own fetch (`open-sse/utils/proxyFetch.ts`), whose `FormData`/`Request` classes differ from the runtime's global `FormData` (same cross-realm class mismatch already fixed once for image edits in #3273); passing a native `FormData` instance through undici's patched fetch made it serialize the body as the literal string `"[object FormData]"` with `Content-Type: text/plain;charset=UTF-8`, which Cloudflare rejects outright. `buildCloudflareWorkerUploadRequest()` (`src/lib/proxyRelay/cloudflareWorkerScript.ts`) now builds the multipart body as a raw `Buffer` with an explicit boundary and `Content-Type: multipart/form-data; boundary=…` header, accepted verbatim by any fetch implementation. Regression guard: `tests/unit/cloudflare-worker-upload-content-type-6416.test.ts` + updated `tests/unit/relay-deploy-5128.test.ts`. @@ -78,45 +81,77 @@ _Living section — bullets land here as PRs merge into `release/v3.8.47` (paral - **chore(open-sse):** removed the vestigial `// @ts-nocheck` directive from `open-sse/utils/usageTracking.ts` ([#6173](https://github.com/diegosouzapw/OmniRoute/pull/6173)) — `tsc` under the standard `typecheck:core` gate reports 0 errors for this 595-line hot-path file (executed for every provider response), so the suppression was no longer needed; removing it restores type-checking on the token-usage extraction/normalization path. (thanks @KooshaPari) - **chore(cli):** the shell-completion cache paths (`readCache`/`refreshCache`/`writeCache`) in `bin/cli/commands/completion.mjs` no longer swallow errors into a bare `catch {}` ([#6257](https://github.com/diegosouzapw/OmniRoute/pull/6257)) — each now binds the error and, when the new `OMNIROUTE_DEBUG_COMPLETION` env var is set, emits a `[omniroute completion]` diagnostic to `stderr`; the caches still fail silently by default so a missing/corrupt cache never breaks tab-completion. (thanks @KooshaPari) - **chore(quality):** `validate-release-green --full-ci` reproduces the full `ci.yml` static gate set locally — the pre-flight now reads `ci.yml` itself and runs every `npm run check:*` from the `lint` / `quality-gate` / `quality-extended` / `docs-sync-strict` / `pr-test-policy` jobs (`--` ratchet flags preserved, `test-masking` against `GITHUB_BASE_REF=main`), skipping only the non-local `pr-evidence`/`codeql-ratchet`. Closes the gap where 11 static base-reds leaked to the v3.8.46 release PR in ~2h of layered CI. Also wired into `nightly-release-green` so a static base-red opens a tracking issue the night it lands. Regression guard: `tests/unit/validate-release-green.test.ts` (+5 `extractCiGates` cases). +- **refactor(usage):** `saveRequestUsage(entry: any)` is now typed with a new `UsageEntry` interface mirroring the `usage_history` columns 1:1 (#3512) — the other stray `any`s in `src/lib/usage/usageHistory.ts` (`getUsageHistory` filter, the `getUsageDb` next-cursor cast, `appendRequestLog`'s legacy `tokens` param, `getRecentLogs`'s catch) were cleaned in the same pass, so the file now sits in the `check:any-budget:t11` zero-`any` allowlist. The DB-entity ↔ TS-interface convention is documented in `docs/architecture/CODEBASE_DOCUMENTATION.md` §11. ### 🙌 Contributors Thanks to everyone whose work landed in v3.8.47: -| Contributor | PRs / Issues | -| -------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -| [@anki1kr](https://github.com/anki1kr) | #6041, #6078 | -| [@arssnndr](https://github.com/arssnndr) | #6163 | -| [@backryun](https://github.com/backryun) | #6154, #6235, #6248, #6331 | -| [@charleszolot](https://github.com/charleszolot) | direct commit / report | -| [@chirag127](https://github.com/chirag127) | #6145, #6189, #6265, #6328, #6400, #6402, #6404, #6405, #6406, #6407, #6408, #6412, #6414, … | -| [@developerjillur](https://github.com/developerjillur) | #6451, #6452, #6541, #6542, #6543, #6545, #6553, #6554, #6558 | -| [@dilneiss](https://github.com/dilneiss) | #6499 | -| [@DKotsyuba](https://github.com/DKotsyuba) | #6193, #6292 | -| [@dtybnrj](https://github.com/dtybnrj) | #6349 | -| [@eidoog](https://github.com/eidoog) | direct commit / report | -| [@hao3039032](https://github.com/hao3039032) | #6351 | -| [@hartmark](https://github.com/hartmark) | #6216 | -| [@Iammilansoni](https://github.com/Iammilansoni) | #6200, #6209, #6245, #6366 | -| [@jmengit](https://github.com/jmengit) | #6372, #6443 | -| [@jordansilly77-stack](https://github.com/jordansilly77-stack) | #6316 | -| [@JxnLexn](https://github.com/JxnLexn) | #6361 | -| [@kanztu](https://github.com/kanztu) | #6181 | -| [@karimalsalah](https://github.com/karimalsalah) | #6291 | -| [@KooshaPari](https://github.com/KooshaPari) | #6144, #6166, #6173, #6257 | -| [@LuisAlejandroVega](https://github.com/LuisAlejandroVega) | #6177 | -| [@makcimbx](https://github.com/makcimbx) | #6303 | -| [@Moseyuh333](https://github.com/Moseyuh333) | #6186 | -| [@pizzav-xyz](https://github.com/pizzav-xyz) | #6648 | -| [@rianonehub](https://github.com/rianonehub) | #6204 | -| [@serverless83](https://github.com/serverless83) | #6212 | -| [@shabeer](https://github.com/shabeer) | direct commit / report | -| [@swingtempo](https://github.com/swingtempo) | #6312 | -| [@Theadd](https://github.com/Theadd) | #6195 | -| [@ThongAccount](https://github.com/ThongAccount) | #6649 | -| [@vinayakkulkarni](https://github.com/vinayakkulkarni) | #6324, #6332 | -| [@VXNCXNX](https://github.com/VXNCXNX) | #6213 | -| [@xz-dev](https://github.com/xz-dev) | #6322, #6336 | +| Contributor | PRs / Issues | +| --- | --- | +| [@alltomatos](https://github.com/alltomatos) | #6703, #6715, #6756, #6757, #6759, #6813, #6819, #6821 | +| [@andrewmunsell](https://github.com/andrewmunsell) | #6774, #6779, #6795 | +| [@AndrianBalanescu](https://github.com/AndrianBalanescu) | #6828, #6829 | +| [@anhdiepmmk](https://github.com/anhdiepmmk) | direct commit / report | +| [@anki1kr](https://github.com/anki1kr) | #6041, #6078 | +| [@arssnndr](https://github.com/arssnndr) | #6163 | +| [@artickc](https://github.com/artickc) | #6363, #6763 | +| [@backryun](https://github.com/backryun) | #6154, #6235, #6248, #6280, #6331, #6675 | +| [@charleszolot](https://github.com/charleszolot) | #6571 | +| [@chirag127](https://github.com/chirag127) | #6145, #6189, #6265, #6328, #6400, #6402, #6404, #6405, #6406, #6407, #6408, #6412, #6414, #6513, #6515, #6516, #6517, #6519, #6521, #6523, #6525, #6526, #6532, #6534, #6546, #6547, #6548, #6549, #6550, #6551, #6552, #6577, #6643, #6644, #6645, #6646, #6703, #6756, #6757, #6769, #6804 | +| [@chy1211](https://github.com/chy1211) | direct commit / report | +| [@developerjillur](https://github.com/developerjillur) | #6451, #6452, #6541, #6542, #6543, #6545, #6553, #6554, #6558 | +| [@dilneiss](https://github.com/dilneiss) | #6499 | +| [@DKotsyuba](https://github.com/DKotsyuba) | #6193, #6292 | +| [@dtybnrj](https://github.com/dtybnrj) | #6349 | +| [@eidoog](https://github.com/eidoog) | direct commit / report | +| [@enjoyer-hub](https://github.com/enjoyer-hub) | #6647 | +| [@hajilok](https://github.com/hajilok) | #6126 | +| [@hamsa0x7](https://github.com/hamsa0x7) | #6317, #6318, #6338 | +| [@hao3039032](https://github.com/hao3039032) | #6351 | +| [@hartmark](https://github.com/hartmark) | #6216 | +| [@herjarsa](https://github.com/herjarsa) | #6640 | +| [@Iammilansoni](https://github.com/Iammilansoni) | #6200, #6209, #6245, #6366 | +| [@ianriizky](https://github.com/ianriizky) | #6072, #6538 | +| [@itiwant](https://github.com/itiwant) | direct commit / report | +| [@janeza2](https://github.com/janeza2) | #6308 | +| [@jmengit](https://github.com/jmengit) | #6372, #6443 | +| [@jordansilly77-stack](https://github.com/jordansilly77-stack) | #6316 | +| [@JxnLexn](https://github.com/JxnLexn) | #6335, #6361 | +| [@kanztu](https://github.com/kanztu) | #6181 | +| [@karimalsalah](https://github.com/karimalsalah) | #6291 | +| [@KooshaPari](https://github.com/KooshaPari) | #6144, #6166, #6173, #6257, #6611, #6632 | +| [@like3213934360-lab](https://github.com/like3213934360-lab) | direct commit / report | +| [@lucasjustinudin](https://github.com/lucasjustinudin) | direct commit / report | +| [@LuisAlejandroVega](https://github.com/LuisAlejandroVega) | #6177 | +| [@makcimbx](https://github.com/makcimbx) | #6303 | +| [@MikeTuev](https://github.com/MikeTuev) | #6586 | +| [@Moseyuh333](https://github.com/Moseyuh333) | #6186, #6294, #6728 | +| [@nowhats-br](https://github.com/nowhats-br) | #6700 | +| [@oyi77](https://github.com/oyi77) | #6309 | +| [@Pitchfork-and-Torch](https://github.com/Pitchfork-and-Torch) | #6747, #6791, #6792 | +| [@pizzav-xyz](https://github.com/pizzav-xyz) | #6648 | +| [@rafpigna](https://github.com/rafpigna) | #6574 | +| [@rianonehub](https://github.com/rianonehub) | #6204 | +| [@ryanngit](https://github.com/ryanngit) | direct commit / report | +| [@samimozcan](https://github.com/samimozcan) | #6753, #6762 | +| [@samir-abis](https://github.com/samir-abis) | direct commit / report | +| [@SeaXen](https://github.com/SeaXen) | #6496, #6678 | +| [@serverless83](https://github.com/serverless83) | #6212 | +| [@shabeer](https://github.com/shabeer) | direct commit / report | +| [@Squawk7777](https://github.com/Squawk7777) | #6565 | +| [@strangersp](https://github.com/strangersp) | #6587 | +| [@swingtempo](https://github.com/swingtempo) | #6312 | +| [@Theadd](https://github.com/Theadd) | #6195 | +| [@Thinkscape](https://github.com/Thinkscape) | #6635 | +| [@ThongAccount](https://github.com/ThongAccount) | #6625, #6649 | +| [@tjengbudi](https://github.com/tjengbudi) | #4009 | +| [@vinayakkulkarni](https://github.com/vinayakkulkarni) | #6324, #6332 | +| [@VXNCXNX](https://github.com/VXNCXNX) | #6213 | +| [@whale9820](https://github.com/whale9820) | direct commit / report | +| [@Witroch4](https://github.com/Witroch4) | #6753, #6762, #6790 | +| [@xz-dev](https://github.com/xz-dev) | #6322, #6323, #6330, #6336, #6702, #6727 | +| [@yinaoxiong](https://github.com/yinaoxiong) | #6805 | --- @@ -3335,6 +3370,7 @@ And thank you to the OmniRoute community for the bug reports, reproductions, and ### Fixed +- **usage:** use xAI's exact provider-reported cost when present instead of always estimating from token counts. (thanks @ryanngit) - **memory:** the `recent` retrieval strategy no longer drops recent memories whose text doesn't overlap the current prompt. It was internally mapped to the `exact` path, which relevance-filtered by the forwarded prompt (`score > 0`), so diff --git a/src/lib/localDb.ts b/src/lib/localDb.ts index 9301182fbb..34468a6cdb 100755 --- a/src/lib/localDb.ts +++ b/src/lib/localDb.ts @@ -788,7 +788,6 @@ export type { // proxy_logs — export query (#3500 slice 4) // --------------------------------------------------------------------------- export { exportProxyLogsSince } from "./db/proxyLogs"; - // --------------------------------------------------------------------------- // Per-connection 429 cooldown wrappers (#5957 / #5958 — Issue 1 follow-ups) // Logic lives in db/providers/rateLimit.ts (Hard Rule #2 — localDb is re-export @@ -797,3 +796,4 @@ export { exportProxyLogsSince } from "./db/proxyLogs"; export { markConnectionRateLimitedUntil, clearConnectionRateLimit } from "./db/providers"; // Provider param filters — denylist/allowlist config per provider/model (#6625) export * from "./db/paramFilters"; +export * from "./db/interceptionRules"; // Per-model web-search/web-fetch interception rules (#3384)