diff --git a/CHANGELOG.md b/CHANGELOG.md index b5d48a1f07e3..7eaec8cb5d58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,23 @@ _Living section — bullets land here as PRs merge into `release/v3.8.47` (paral - **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). +- **feat(ws):** the live-dashboard WebSocket server now auto-starts in-process (via `instrumentation-node.ts`) across every deployment mode — dev, production, Docker, Electron — with no separate sidecar script; the default WS port moved from 20129 to **20132** to avoid colliding with `API_PORT` in split-port setups, the deprecated `OMNIROUTE_DISABLE_LIVE_WS` env was consolidated into `OMNIROUTE_ENABLE_LIVE_WS` (default enabled), and the WS path is now derived from `NEXT_PUBLIC_LIVE_WS_PUBLIC_URL`'s pathname (`/live-ws` fallback) (#6072 — thanks @ianriizky). +- **feat(compression):** new **omniglyph** engine (context-as-image) — renders system prompt, tool docs, and dense history as compact PNG pages the model reads instead of text (~10× fewer tokens on the converted block; 59–70% end-to-end measured). Works stacked with RTK/Caveman (`stackPriority: 90`) or standalone (`mode: omniglyph`); restricted to Claude Fable 5 over the direct Anthropic route, fail-closed gates with `skip:` techniques, preview (`stable: false`, off by default) (#6556). Dependency bumped to `omniglyph@^1.0.2` for upstream ReDoS fixes (#6661). +- **feat(sandbox):** the skill sandbox gained a container-provider abstraction that auto-detects and uses the best native runtime per host — Apple Container (macOS 26+), WSL container (`wslc.exe`), OrbStack, Podman — instead of hardcoding `docker run`, removing the Docker Desktop requirement on macOS/Windows (#6611 — thanks @KooshaPari). +- **fix(sse):** skip `thinkingConfig` for Gemma models on the OpenAI→Gemini path so OpenAI-shape clients no longer get a 400 from Vertex. (thanks @chy1211) +- **feat(xai):** route xAI clients to Grok's native `/v1/responses` endpoint instead of the chat-completions bridge. (thanks @ryanngit) +- **feat(models):** add a Settings → AI "Model Overrides" UI plus `/api/model-capability-overrides` CRUD and a `model_capability_overrides` table, letting operators set a manual max-output-token override per provider/model (#6727 — thanks @xz-dev). +- **feat(resilience):** operator-configurable account rotation policy — a new `rotationConfig` layer lets operators tune how connections rotate on failure, wired into `accountFallback` (#6763 — thanks @artickc). +- **chore(cursor): add Grok 4.5 effort/fast model IDs** (#6774 — thanks @andrewmunsell). +- **feat(codex):** Codex provider model discovery now fetches the live catalog from `chatgpt.com/backend-api/codex/models` using Codex-shaped headers, falling back to a GitHub-hosted model manifest and then to the local static catalog when the live/GitHub sources are unavailable or return an unexpected shape — new `src/app/api/providers/[id]/models/discovery/codex.ts` (normalization, version-gating, merge/enrich against the local catalog) covered by `tests/unit/provider-models-discovery-split.test.ts` and `tests/unit/provider-models-route-codex.test.ts` (#6776 — thanks @JxnLexn). +- **feat(cursor):** register the Opus 4.8, Fable 5, and Sonnet 5 model families for the Cursor Agent provider so the latest Claude/Fable model ids route correctly (#6779 — thanks @andrewmunsell). +- **Changelog fragments (`changelog.d/`)**: PRs now add their changelog entry as a new fragment file (`changelog.d/{features|fixes|maintenance}/-.md`) instead of editing `CHANGELOG.md` — two PRs never touch the same file, structurally eliminating the CHANGELOG-eat merge conflicts that forced a re-sync push + full CI re-run after every sibling merge (O(N²) CI runs in a merge-storm). `scripts/release/aggregate-changelog.mjs` (npm run changelog:aggregate) folds fragments into the living section at release reconciliation, and `check:changelog-integrity` now also validates fragment well-formedness. Regression guard: `tests/unit/changelog-fragments.test.ts`. +- **feat(proxy):** add a latency-optimized proxy rotation strategy that ranks pool entries by measured round-trip latency, extending the existing round-robin/random/sticky proxy-pool selection (#6798 — thanks @iamraydoan). +- **feat(fusion):** the fusion judge may now draw on its own knowledge and override the panel when every panel answer is wrong or incomplete, instead of being restricted to synthesizing only from panel output (#6804 — thanks @chirag127). +- **feat(dashboard):** search box on the Playground's raw model `` (#4086) — the shared `ModelSelectModal` (combo builder + CLI-code cards) already had search, but Playground's `StudioConfigPane` model dropdown stayed a flat unsearchable list, unusable once a provider like OpenRouter contributed 50+ models. Typing now filters the dropdown (Turkish-safe accent/case-insensitive match via `matchesSearch`), while the currently selected model always stays pinned in the list even if it no longer matches the query, so typing never silently swaps the active selection. Reuses the existing `common.search` i18n key (already translated in all 42 locales) — no new translation key needed. Regression guard: `tests/unit/playground-model-selection-3731.test.ts` (`filterModelsByQuery`), `tests/unit/ui/playground-model-search-4086.test.tsx`. diff --git a/changelog.d/features/6818-antigravity-weekly-quota.md b/changelog.d/features/6818-antigravity-weekly-quota.md deleted file mode 100644 index 84abe02d9de1..000000000000 --- a/changelog.d/features/6818-antigravity-weekly-quota.md +++ /dev/null @@ -1 +0,0 @@ -- **feat(usage):** Antigravity/agy quota widget now surfaces the **weekly** window alongside the existing per-model 5-hour window ([#4017](https://github.com/diegosouzapw/OmniRoute/issues/4017)) — the weekly limit isn't part of the per-model `retrieveUserQuota` response the fetcher already calls; it only appears in a separate, undocumented `retrieveUserQuotaSummary` RPC that groups models into families ("Gemini Models", "Claude and GPT models") with one weekly bucket per family. A new `usage/antigravityWeeklyQuota.ts` leaf fetches that RPC (cached, best-effort — a failure or unavailable RPC never breaks the existing per-model quotas) and parses the weekly bucket per group into `gemini_weekly`/`claude_gpt_weekly` quota entries, merged into the same `quotas` map the widget already renders generically. Regression guard: `tests/unit/antigravity-weekly-quota-4017.test.ts` (bucket parsing, the alternate `quotaSummary`-nested envelope, and end-to-end merge via `getUsageForProvider`). diff --git a/changelog.d/features/6820-codex-effort-model-echo.md b/changelog.d/features/6820-codex-effort-model-echo.md deleted file mode 100644 index d9646f81a31d..000000000000 --- a/changelog.d/features/6820-codex-effort-model-echo.md +++ /dev/null @@ -1 +0,0 @@ -- **feat(codex):** Codex CLI compatibility shim — the Responses API `response.created`/`response.in_progress`/`response.completed` payloads now carry a `model` field (previously absent), and for Codex-CLI-originated requests it echoes the client-requested, effort-suffixed model id (e.g. `gpt-5.5-xhigh`) instead of the bare upstream id (`gpt-5.5`), so the Codex CLI status line/model button shows the active reasoning effort ([#3697](https://github.com/diegosouzapw/OmniRoute/issues/3697)). `openaiToOpenAIResponsesResponse` (`open-sse/translator/response/openai-responses.ts`) now threads the upstream model into the Responses event objects; a new `isCodexOriginatedHeaders()` (`open-sse/config/codexIdentity.ts`, reusing PR #3481's `originator`/User-Agent detection) makes chatCore's existing opt-in `echoRequestedModelName` (#1311) model-echo pipeline fire automatically for Codex clients regardless of the setting, detected by request headers so it still applies when `codex/gpt-5.5-xhigh` is routed through a combo to a non-codex upstream; `echoModelInObject`/`echoModelInSseLine` (`open-sse/services/responseModelEcho.ts`) now also rewrite the nested `response.model` field the Responses API uses. `/v1/models` still returns `models: []` for Codex (unchanged). Regression guard: `tests/unit/codex-effort-model-echo-3697.test.ts`. diff --git a/changelog.d/features/6823-zai-web-cookie-provider.md b/changelog.d/features/6823-zai-web-cookie-provider.md deleted file mode 100644 index 57100fc05cba..000000000000 --- a/changelog.d/features/6823-zai-web-cookie-provider.md +++ /dev/null @@ -1 +0,0 @@ -- **Z.ai Web (free web-session provider)**: new `zai-web` web-cookie provider drives the free chat.z.ai consumer chat UI via a pasted browser session cookie, distinct from the existing API-key `zai`/`glm`/`glm-cn`/`glmt` providers (`api.z.ai`) — modeled on the `doubao-web`/`venice-web` cookie executors and the pre-existing `chatglm-web` credential requirement/token-extraction entries. `ZaiWebExecutor` (`open-sse/executors/zai-web.ts`) posts to `chat.z.ai/api/chat/completions` with the cookie forwarded both as `Cookie` and as `Authorization: Bearer `, and normalizes both z.ai's internal `delta_content`/`phase` SSE envelope and a pass-through OpenAI-shaped `choices[].delta` frame into standard chat-completion chunks. Registered in `WEB_COOKIE_PROVIDERS`, `WEB_SESSION_CREDENTIAL_REQUIREMENTS`, the provider registry (`zai-web` entry, GLM-4.6/4.5/4.5V models), and `tokenExtractionConfig.ts` for in-app cookie capture. Regression guard: `tests/unit/executor-zai-web.test.ts` (16 tests — token extraction, frame parsing for both SSE shapes, streaming and non-streaming aggregation, error paths). (#4056) diff --git a/changelog.d/fixes/6272-6272-mimo-proxy.md b/changelog.d/fixes/6272-6272-mimo-proxy.md deleted file mode 100644 index 37b11868be9b..000000000000 --- a/changelog.d/fixes/6272-6272-mimo-proxy.md +++ /dev/null @@ -1 +0,0 @@ -- fix(providers): honor a provider-level proxy assigned to no-auth providers like MiMoCode Free (#6272) diff --git a/changelog.d/fixes/6276-toolcall-args-logs.md b/changelog.d/fixes/6276-toolcall-args-logs.md deleted file mode 100644 index 90b6bde61b24..000000000000 --- a/changelog.d/fixes/6276-toolcall-args-logs.md +++ /dev/null @@ -1 +0,0 @@ -- fix(api): merge tool_call continuation deltas that carry only `id` (no `index`) so tool-call arguments are no longer split/lost in request/response logs (#6276) diff --git a/changelog.d/fixes/6280-lmarena-arena-modernize.md b/changelog.d/fixes/6280-lmarena-arena-modernize.md deleted file mode 100644 index 4ba53979bc7e..000000000000 --- a/changelog.d/fixes/6280-lmarena-arena-modernize.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(providers):** modernize the `lmarena` provider for the Arena.ai rebrand — route chat through `arena.ai` create-evaluation with Chrome TLS impersonation, seed a static Direct-chat Text/Search + Image catalog, and keep the `lmarena`/`lma` wire id for back-compat ([#6280](https://github.com/diegosouzapw/OmniRoute/pull/6280)) — thanks @backryun diff --git a/changelog.d/fixes/6308-web-model-discovery.md b/changelog.d/fixes/6308-web-model-discovery.md deleted file mode 100644 index a452c1ae73ac..000000000000 --- a/changelog.d/fixes/6308-web-model-discovery.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(providers):** web-provider model discovery updated — qwen-web uses the slash-terminated models endpoint (avoiding a blocked 307 redirect), and kimi-web matches the current request shape (POST with bearer + `kimi-auth` cookie replay) with its catalog refreshed to the current non-agent models (#6308 — thanks @janeza2). diff --git a/changelog.d/fixes/6323-log-detail-stale-reopen.md b/changelog.d/fixes/6323-log-detail-stale-reopen.md deleted file mode 100644 index ec1c53ca2f6a..000000000000 --- a/changelog.d/fixes/6323-log-detail-stale-reopen.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(logs):** the request-log detail modal no longer reopens by itself after being closed — a stale in-flight detail refresh resolved after close and re-triggered the modal open state (#6323 — thanks @xz-dev). diff --git a/changelog.d/fixes/6330-sensenova-token-plan.md b/changelog.d/fixes/6330-sensenova-token-plan.md deleted file mode 100644 index 3ef26dea2bc2..000000000000 --- a/changelog.d/fixes/6330-sensenova-token-plan.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(providers):** update SenseNova Token Plan support — register the token-plan model ids/constants and adjust the SenseNova registry so token-plan accounts route correctly (#6330 — thanks @xz-dev). diff --git a/changelog.d/fixes/6409-6409-build-ram.md b/changelog.d/fixes/6409-6409-build-ram.md deleted file mode 100644 index 4baeb797a632..000000000000 --- a/changelog.d/fixes/6409-6409-build-ram.md +++ /dev/null @@ -1 +0,0 @@ -- fix(docs): document Turbopack build memory tradeoff and `OMNIROUTE_USE_TURBOPACK=0` webpack fallback for RAM-constrained machines (#6409) diff --git a/changelog.d/fixes/6479-6479-compression-pipeline.md b/changelog.d/fixes/6479-6479-compression-pipeline.md deleted file mode 100644 index dba609406663..000000000000 --- a/changelog.d/fixes/6479-6479-compression-pipeline.md +++ /dev/null @@ -1 +0,0 @@ -- fix(compression): surface silently-dropped stacked-pipeline steps (session-dedup, ccr) and stop the aggregate inflation guard from misfiring on a genuine no-op (#6479, #6480, #6491) diff --git a/changelog.d/fixes/6524-6524-reasoning-buffer-clamp.md b/changelog.d/fixes/6524-6524-reasoning-buffer-clamp.md deleted file mode 100644 index 9f551de90cfe..000000000000 --- a/changelog.d/fixes/6524-6524-reasoning-buffer-clamp.md +++ /dev/null @@ -1 +0,0 @@ -- fix(providers): honor the `max_token` capability override in the reasoning-token-buffer output cap (#6524) diff --git a/changelog.d/fixes/6538-tier-flow-svg-public.md b/changelog.d/fixes/6538-tier-flow-svg-public.md deleted file mode 100644 index e3d3f76cef6c..000000000000 --- a/changelog.d/fixes/6538-tier-flow-svg-public.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(dashboard):** the onboarding tier-flow diagram rendered broken — its SVGs lived in the repo-root `images/` (not a served path); moved to `public/images/` so Next.js serves them (#6538 — thanks @ianriizky). diff --git a/changelog.d/fixes/6586-preserve-server-tool-names.md b/changelog.d/fixes/6586-preserve-server-tool-names.md deleted file mode 100644 index 62ee75c23484..000000000000 --- a/changelog.d/fixes/6586-preserve-server-tool-names.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(sse):** server-tool literal names (e.g. `web_search`) are preserved in message history and `tool_choice` instead of being namespaced/rewritten, so follow-up turns referencing those tools keep working (#6586 — thanks @MikeTuev). diff --git a/changelog.d/fixes/6628-6628-sqljs-adapter.md b/changelog.d/fixes/6628-6628-sqljs-adapter.md deleted file mode 100644 index 55d6a3ce9ac2..000000000000 --- a/changelog.d/fixes/6628-6628-sqljs-adapter.md +++ /dev/null @@ -1,2 +0,0 @@ -- fix(db): share one in-flight sql.js load across concurrent `preInitSqlJs()` callers to stop the boot-time thundering-herd re-decode of the whole database file (#6628) -- fix(db): unwrap lone named-parameter objects before `sql.js` `stmt.bind()` so `@`/`:`/`$`-style named placeholders bind correctly instead of throwing "Wrong API use" (#6802) diff --git a/changelog.d/fixes/6632-probe-restore-loop-cycle-breaker.md b/changelog.d/fixes/6632-probe-restore-loop-cycle-breaker.md deleted file mode 100644 index 45094d374230..000000000000 --- a/changelog.d/fixes/6632-probe-restore-loop-cycle-breaker.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(db): break probe-failed/restore loop on large storage.sqlite** (#6632 — thanks @KooshaPari). diff --git a/changelog.d/fixes/6637-6637-combo-kimi-fallback.md b/changelog.d/fixes/6637-6637-combo-kimi-fallback.md deleted file mode 100644 index be7cd2ed0b12..000000000000 --- a/changelog.d/fixes/6637-6637-combo-kimi-fallback.md +++ /dev/null @@ -1 +0,0 @@ -- fix(routing): recognize Kimi-style "exceeded model token limit" 400 as context overflow so combo fallback continues to the next target (#6637) diff --git a/changelog.d/fixes/6647-winget-claude-detect.md b/changelog.d/fixes/6647-winget-claude-detect.md deleted file mode 100644 index c0ffef13244b..000000000000 --- a/changelog.d/fixes/6647-winget-claude-detect.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(cli):** Claude Code installed via WinGet is now detected on Windows (the WinGet install path was missing from the binary lookup) (#6647 — thanks @enjoyer-hub). diff --git a/changelog.d/fixes/6675-remove-obsolete-providers.md b/changelog.d/fixes/6675-remove-obsolete-providers.md deleted file mode 100644 index 4c4f4bcf1c05..000000000000 --- a/changelog.d/fixes/6675-remove-obsolete-providers.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(providers):** removed obsolete/defunct providers from the catalog (glhf, kluster, cablyai, inclusionai) (#6675 — thanks @backryun). diff --git a/changelog.d/fixes/6698-count-gate-rejected-usage.md b/changelog.d/fixes/6698-count-gate-rejected-usage.md deleted file mode 100644 index bb1288c40736..000000000000 --- a/changelog.d/fixes/6698-count-gate-rejected-usage.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(sse):** requests rejected before `handleChatCore` (circuit-breaker/cooldown gate or combo with all targets exhausted) are now recorded in `usage_history` too, so a key whose traffic was entirely gate-rejected no longer shows "zero requests" in the per-API-key usage counter (#6698). diff --git a/changelog.d/fixes/6704-unwrap-bare-function-tool.md b/changelog.d/fixes/6704-unwrap-bare-function-tool.md deleted file mode 100644 index 85b21b7c5bf9..000000000000 --- a/changelog.d/fixes/6704-unwrap-bare-function-tool.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(sse):** unwrap bare `{function:{…}}` tools so OpenAI-shape clients no longer have tools silently dropped in Claude translation. (thanks @samir-abis) diff --git a/changelog.d/fixes/6706-codex-oauth-bare-email-dedup.md b/changelog.d/fixes/6706-codex-oauth-bare-email-dedup.md deleted file mode 100644 index 4eca2c782857..000000000000 --- a/changelog.d/fixes/6706-codex-oauth-bare-email-dedup.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(oauth):** stop merging distinct Codex OAuth logins that share an email but lack a verifiable account id, preventing silent token overwrite. (thanks @lucasjustinudin) diff --git a/changelog.d/fixes/6710-codex-200-sse-capacity-error.md b/changelog.d/fixes/6710-codex-200-sse-capacity-error.md deleted file mode 100644 index e84653d7bd56..000000000000 --- a/changelog.d/fixes/6710-codex-200-sse-capacity-error.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(codex):** detect "model at capacity"/overloaded errors embedded in a 200-OK SSE stream and surface them as a real error so account fallback rotates, instead of passing them through as a successful response. (thanks @ryanngit) diff --git a/changelog.d/fixes/6712-volcengine-kimi-max-tokens.md b/changelog.d/fixes/6712-volcengine-kimi-max-tokens.md deleted file mode 100644 index 29586d549c68..000000000000 --- a/changelog.d/fixes/6712-volcengine-kimi-max-tokens.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(volcengine):** clamp `max_tokens` to the VolcEngine Ark endpoint cap for the Kimi model so oversized values no longer 400. (thanks @whale9820) diff --git a/changelog.d/fixes/6713-antigravity-abort-finish-reason.md b/changelog.d/fixes/6713-antigravity-abort-finish-reason.md deleted file mode 100644 index f94984faf663..000000000000 --- a/changelog.d/fixes/6713-antigravity-abort-finish-reason.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(antigravity):** surface aborted/malformed Gemini tool calls (e.g. `MALFORMED_FUNCTION_CALL`) as an explicit non-`end_turn` finish reason instead of a silent clean completion. (thanks @anhdiepmmk) diff --git a/changelog.d/fixes/6714-reasoning-buffer-cap-aware.md b/changelog.d/fixes/6714-reasoning-buffer-cap-aware.md deleted file mode 100644 index a67b36333cee..000000000000 --- a/changelog.d/fixes/6714-reasoning-buffer-cap-aware.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(routing):** the reasoning-token headroom buffer clamps to the model's explicit output cap instead of inflating past it, and `getExplicitModelOutputCap` falls through to the registry/spec cap when a synced capability row exists without a numeric `limit_output` ([#6714](https://github.com/diegosouzapw/OmniRoute/pull/6714)) — thanks @xz-dev diff --git a/changelog.d/fixes/6717-cli-health-monitoring-route.md b/changelog.d/fixes/6717-cli-health-monitoring-route.md deleted file mode 100644 index 80e5ad7ec7db..000000000000 --- a/changelog.d/fixes/6717-cli-health-monitoring-route.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(api):** `omniroute health` (and `health components`/`health watch`) returned `Error: HTTP 404` ([#6677](https://github.com/diegosouzapw/OmniRoute/issues/6677)) — `bin/cli/commands/health.mjs` called `apiFetch("/api/health", ...)`, a route that was moved to `GET /api/monitoring/health` (`src/app/api/monitoring/health/route.ts`) without updating the CLI; `src/app/api/health/` on disk only has `degradation/route.ts` and `ping/route.ts`, no top-level handler. `runHealthCommand()`/`runHealthComponentsCommand()` now call `/api/monitoring/health` and read its actual payload shape (`activeConnections`, `circuitBreakers: {open, halfOpen, closed}`, `memoryUsage`) instead of the old, nonexistent `requests`/`breakers`/`cache`/`memory` fields. Regression guard: `tests/unit/cli-health-monitoring-route.test.ts`. diff --git a/changelog.d/fixes/6718-reasoningcontrols-case-collision.md b/changelog.d/fixes/6718-reasoningcontrols-case-collision.md deleted file mode 100644 index 4c4449755fc5..000000000000 --- a/changelog.d/fixes/6718-reasoningcontrols-case-collision.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(startup):** webpack build broke on case-insensitive filesystems (macOS APFS default, Windows) with a casing-collision warning plus "not exported" errors in `StudioConfigPane.tsx`/`ChatTab.tsx` (#6584) — `src/app/(dashboard)/dashboard/playground/components/ReasoningControls.tsx` (the component) and `reasoningControls.ts` (the utils module) shared the same lower-cased stem in the same directory, and two importers used the extensionless form `from "./reasoningControls"`, the exact resolution path that becomes ambiguous once casing is folded. Renamed the utils module to `reasoningControlUtils.ts` (no collision) and updated the 3 import sites. Regression guard: `tests/unit/case-collision-6584.test.ts` (scans `src/`/`open-sse/` for any same-directory, case-only filename collision). (#6584) diff --git a/changelog.d/fixes/6720-turbopack-agentskills-warning.md b/changelog.d/fixes/6720-turbopack-agentskills-warning.md deleted file mode 100644 index aa9fc2e42ba4..000000000000 --- a/changelog.d/fixes/6720-turbopack-agentskills-warning.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(build):** Turbopack production build emitted an "Overly broad patterns can lead to build performance issues" warning per entry point importing `src/lib/agentSkills/generator.ts` (603 warnings reported on v3.8.46, up from 379 on v3.8.45) ([#6582](https://github.com/diegosouzapw/OmniRoute/issues/6582)) — `generator.ts`'s `outputBase` is built as `path.isAbsolute(outputDir) ? outputDir : path.join(process.cwd(), outputDir)`, where `outputDir` is a runtime function parameter, not a compile-time literal, so Turbopack's build-time file-tracing analyzer can't statically narrow the several dynamic `readdirSync`/`rmSync`/`readFileSync`/`writeFileSync` call sites a few lines below and falls back to a project-wide glob; #6366's commit message claimed to "anchor the base path with a literal" but the shipped code never did. Since this fs access is legitimate and bounded (`skills//SKILL.md`, ~48 known IDs), `next.config.mjs`'s `turbopack.ignoreIssue` (Next.js 16.2+) now suppresses this specific, known-benign diagnostic, mirroring the existing `webpack.ignoreWarnings`/`isNextIntlExtractorDynamicImportWarning` precedent already in the same file for the webpack path. Regression guard: `tests/unit/next-config.test.ts` (asserts the `turbopack.ignoreIssue` rule shape targeting `src/lib/agentSkills/**`). diff --git a/changelog.d/fixes/6721-codex-spark-image-drop.md b/changelog.d/fixes/6721-codex-spark-image-drop.md deleted file mode 100644 index d814d8bd3976..000000000000 --- a/changelog.d/fixes/6721-codex-spark-image-drop.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(providers):** Codex Desktop requests to `gpt-5.3-codex-spark` failed with `[400]: Tool 'image_generation' is not supported with gpt-5.3-codex-spark`, even on paid-plan accounts ([#6651](https://github.com/diegosouzapw/OmniRoute/issues/6651)) — `CodexExecutor.transformRequest` (`open-sse/executors/codex.ts`) only dropped the Codex Desktop-injected `image_generation` hosted tool when `isCodexFreePlan()` matched the account's plan, with no awareness that Spark-scope Codex models reject `image_generation` upstream regardless of plan. `dropImageGeneration` now also drops it when `getCodexModelScope(model) === "spark"` (the existing Spark classifier from `open-sse/config/codexQuotaScopes.ts`), independent of account plan. Regression guard: `tests/unit/codex-spark-image-generation.test.ts` (thanks @alltomatos for independently catching and fixing it via #6819). diff --git a/changelog.d/fixes/6722-quota-card-fixed-order.md b/changelog.d/fixes/6722-quota-card-fixed-order.md deleted file mode 100644 index ea2d2f7bbdb5..000000000000 --- a/changelog.d/fixes/6722-quota-card-fixed-order.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(providers):** the provider quota card's weekly/session bars re-sorted by remaining percentage instead of staying in a fixed, deterministic order ([#6687](https://github.com/diegosouzapw/OmniRoute/issues/6687)) — `QuotaCardExpanded.tsx`'s `sortQuotasByRemaining()` (added in #5977) was applied unconditionally via `useMemo(() => sortQuotasByRemaining(quotas), [quotas])`, undoing the deterministic `CODEX_QUOTA_ORDER`/`GLM_QUOTA_ORDER` window order `quotaParsing.ts`'s `sortCodexOrder()`/`sortGlmOrder()` (added in #6336) already established for Codex and the GLM family — since #6336 never touched `QuotaCardExpanded.tsx`, the two orderings never composed, so e.g. a Codex `session` window with less headroom than `weekly` rendered after it instead of staying first. A new `hasFixedQuotaOrder()` (`quotaParsing.ts`) and `resolveQuotaDisplayOrder()` (`QuotaCardExpanded.tsx`) now skip the remaining-% re-sort for providers with a fixed window order, threading `providerId` from `QuotaCard.tsx` through to the display layer; every other provider still gets the remaining-% sort. Regression guard: `tests/unit/quota-card-expanded-fixed-order-6687.test.ts`. diff --git a/changelog.d/fixes/6723-i18n-pt-br-backfill.md b/changelog.d/fixes/6723-i18n-pt-br-backfill.md deleted file mode 100644 index aca0c58e2440..000000000000 --- a/changelog.d/fixes/6723-i18n-pt-br-backfill.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(i18n):** pt-BR was missing 194 UI keys present in `en.json` — a real, silent data-sync gap, not covered by any duplicate/mislabeled #6694 (that issue's 9 `providers.*` keys are disjoint, present-but-untranslated sentinels caused by a separate `providerText()` fallback bug) ([#6695](https://github.com/diegosouzapw/OmniRoute/issues/6695)) — `scripts/i18n/sync-ui-keys.mjs` (which mirrors newly-added `en.json` keys into every locale) wasn't re-run after recent `en.json` additions, and the CI `i18n:check-ui-coverage` gate only fails a locale below an 80% threshold, so pt-BR stayed green at 93.8% coverage despite the gap. Backfilled all 194 missing keys into `src/i18n/messages/pt-BR.json` (translated to Brazilian Portuguese, no leftover `__MISSING__` markers) via `npm run i18n:sync-ui -- --locale=pt-BR` + manual translation. Regression guard: `tests/unit/i18n-pt-br.test.ts` (new case asserting full `en.json`→`pt-BR.json` key parity, so a future drift fails a fast unit test instead of silently degrading the coverage percentage). diff --git a/changelog.d/fixes/6725-lazy-ioredis-mcp.md b/changelog.d/fixes/6725-lazy-ioredis-mcp.md deleted file mode 100644 index ba6238f5ec08..000000000000 --- a/changelog.d/fixes/6725-lazy-ioredis-mcp.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(startup):** `omniroute --mcp` crashed at Node ESM link time with `ERR_MODULE_NOT_FOUND` for `ioredis` on installs where the published MCP bundle didn't happen to have `ioredis` rescued from a parent `node_modules` ([#6559](https://github.com/diegosouzapw/OmniRoute/issues/6559)) — `src/shared/utils/rateLimiter.ts` had a top-level static `import Redis from "ioredis"`; that module is only ever reached via a lazy `await import(...)` several call-sites deep in the MCP tool chain, but esbuild's `--packages=external` bundling of the MCP server (`scripts/build/prepublish.ts` Step 8.5) still hoisted rateLimiter.ts's own static import into a real top-level ESM import in the compiled `dist/open-sse/mcp-server/server.js`, forcing Node to resolve `ioredis` at module-link time — before any `--mcp` startup code runs — and `ioredis` is not guaranteed to ship in the MCP-only bundle's `node_modules`. `getRedisClient()` now lazily imports `ioredis` on first use (matching the established soft-dependency pattern in `src/lib/quota/redisQuotaStore.ts`) while still throwing synchronously when Redis isn't configured. Regression guard: `tests/unit/build/mcp-bundle-no-eager-ioredis.test.ts` (bundles the real MCP server entrypoint with the exact publish-time esbuild flags and asserts no top-level static `ioredis` import remains, while the pre-existing lazy `await import("ioredis")` in `redisQuotaStore.ts` stays intact). diff --git a/changelog.d/fixes/6726-kiro-adaptive-thinking-allowlist.md b/changelog.d/fixes/6726-kiro-adaptive-thinking-allowlist.md deleted file mode 100644 index e31c103661af..000000000000 --- a/changelog.d/fixes/6726-kiro-adaptive-thinking-allowlist.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(providers):** Kiro sent the adaptive-thinking `additionalModelRequestFields` envelope for `claude-sonnet-4.5`/`claude-haiku-4.5`, which Kiro/CodeWhisperer rejects upstream with a raw `[400]: additionalModelRequestFields is not supported for this model` ([#6576](https://github.com/diegosouzapw/OmniRoute/issues/6576)) — `buildKiroPayload()` (`open-sse/translator/request/openai-to-kiro.ts`) gated the field on the generic Anthropic-API `supportsReasoning()` capability flag, which is `true` for both models on Anthropic's direct API but does not reflect what Kiro's CodeWhisperer backend actually accepts; only `claude-sonnet-5` is confirmed adaptive-thinking-capable there. A new Kiro-specific allowlist (`supportsKiroAdaptiveThinking()` in `open-sse/translator/request/openai-to-kiro/adaptiveThinking.ts`) now gates the envelope instead. Regression guard: `tests/unit/repro-6576-kiro-thinking-unsupported-model.test.ts`. diff --git a/changelog.d/fixes/6729-cursor-subagent-strip-cloud-base.md b/changelog.d/fixes/6729-cursor-subagent-strip-cloud-base.md deleted file mode 100644 index 4cd79fd8a317..000000000000 --- a/changelog.d/fixes/6729-cursor-subagent-strip-cloud-base.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(translator):** Cursor's local **Subagent** tool call is no longer rejected with `cloud_base_branch may only be specified when environment equals cloud` — the Responses→Chat tool-arg cleanup (`stripEmptyOptionalToolArgs`) was scoped to Claude Code's `Read` tool only, so Cursor's `Subagent` tool passed through with the cloud-only `cloud_base_branch: ""` (Cursor treats an empty string as "specified" and rejects the call before starting the local subagent). The cleanup now covers an allowlist of `Read` + `Subagent`; arbitrary tools are still left untouched (empty strings/arrays can be valid payloads for them). Regression guard: `tests/unit/openai-responses-subagent-strip-2446.test.ts`. (thanks @like3213934360-lab) diff --git a/changelog.d/fixes/6730-glm-split-tool-name.md b/changelog.d/fixes/6730-glm-split-tool-name.md deleted file mode 100644 index ad807f6272cb..000000000000 --- a/changelog.d/fixes/6730-glm-split-tool-name.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(translator):** GLM 5.2 (and other OpenAI-compatible upstreams that stream a tool call's `id` and `function.name` in **separate** SSE chunks) no longer produce an empty tool name / `No such tool available:` error through the Claude `/messages` path — the `openai-to-claude` streaming translator emitted `content_block_start` immediately on the id-only chunk with an empty `name`, and the Claude SSE protocol cannot patch a block after it is emitted, so the later name-only chunk was silently dropped. It now **defers** `content_block_start` until the tool name arrives (falling back to starting the block when arguments arrive first), so the emitted `tool_use` always carries the real name. Regression guard: `tests/unit/openai-to-claude-glm-split-tool-name-2077.test.ts`. (thanks @itiwant) diff --git a/changelog.d/fixes/6731-apikey-429-quota-exhausted.md b/changelog.d/fixes/6731-apikey-429-quota-exhausted.md deleted file mode 100644 index bdfabc45ef33..000000000000 --- a/changelog.d/fixes/6731-apikey-429-quota-exhausted.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(resilience):** OmniRoute didn't respect an exhausted Ollama Cloud (or any other apikey-category provider) quota — it retried the account seconds later instead of waiting out the real reset window ([#6638](https://github.com/diegosouzapw/OmniRoute/issues/6638)) — `shouldPreserveQuotaSignalsFor429()`/`checkFallbackError()` (`open-sse/services/accountFallback.ts`) only applied body-text quota classification (daily/monthly/weekly quota-exhausted detection) to OAuth-category providers; apikey-category 429s (Ollama Cloud, OpenAI, etc.) always fell through to the generic short rate-limit cooldown regardless of what the error body said, and `parseRetryFromErrorText()` also had no support for day-granularity reset hints ("Your quota will reset in 3 days.") — only Xh/Ym/Zs combos. An explicit quota-exhausted signal in the body (`looksLikeQuotaExhausted()`) now overrides the apikey-category default via the new `shouldPreserveQuotaSignals()` (`open-sse/services/quotaResetParsing.ts`), and `parseDayGranularityResetMs()` parses whole-day reset countdowns so the real multi-day window is honored instead of a few seconds of backoff. Regression guard: `tests/unit/issue-6638-ollama-quota.test.ts` + 2 aligned `tests/unit/account-fallback-service.test.ts` cases that previously asserted the buggy rate_limit_exceeded/undefined-dailyQuotaExhausted behavior for apikey-provider quota text. diff --git a/changelog.d/fixes/6732-fp-pinned-combo-resolve.md b/changelog.d/fixes/6732-fp-pinned-combo-resolve.md deleted file mode 100644 index 47f790681c5c..000000000000 --- a/changelog.d/fixes/6732-fp-pinned-combo-resolve.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(resilience):** a combo step "pinned" to one fingerprint account (mimocode/mcode/opencode multi-account providers) never actually resolved to that account, so it couldn't fail over when the pinned account was depleted ([#6696](https://github.com/diegosouzapw/OmniRoute/issues/6696), relates #6612) — the combo builder UI encodes an account pin as a composite connectionId (`${rowId}|fp|${fingerprint}`, `src/lib/combos/builderOptions.ts`), but `expandTargetsByFingerprints()` (`open-sse/services/combo/fingerprintExpansion.ts`) looked that composite string up directly in `connectionById` (keyed by real DB row ids), got `undefined`, and passed the target through unchanged, still carrying the bogus composite id — so downstream credential resolution could never match it either. `expandTargetsByFingerprints()` now splits the `|fp|` composite id back into the real connection row id + the pinned fingerprint (new `splitFingerprintPin()` helper) before any lookup, resolving the target to the real connectionId (with the pinned fingerprint carried on the new `pinnedFingerprint` field) instead of the inert composite string. Regression guard: `tests/unit/combo-fingerprint-pin-6696.test.ts`. diff --git a/changelog.d/fixes/6735-responses-commentary-event-frame.md b/changelog.d/fixes/6735-responses-commentary-event-frame.md deleted file mode 100644 index 6dce5931c9df..000000000000 --- a/changelog.d/fixes/6735-responses-commentary-event-frame.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(api):** Responses passthrough emitted event-only SSE frames (no `data:` line) for every dropped commentary event, breaking the OpenAI Python SDK's `sse.json()` parser ([#6561](https://github.com/diegosouzapw/OmniRoute/issues/6561)), follow-up to #6199/#6232 — the commentary-drop `continue;` branches in `open-sse/utils/stream.ts` skipped the `data:` line for a dropped commentary event but never cleared the already-buffered `event:` line for that same frame, so the next blank line flushed the stale `event:` line alone. Both drop sites now call `clearPendingPassthroughEvent()` before `continue`, discarding the buffered prefix along with the dropped payload; the commentary-drop decision itself was extracted into a new `open-sse/utils/responsesCommentaryDrop.ts` so the fix does not grow the frozen `stream.ts`. Regression guard: `tests/unit/responses-commentary-event-frame-6561.test.ts` (realistic `event:\ndata:\n\n` frames — the existing #6199 test only used bare `data:` lines and never exercised this path). diff --git a/changelog.d/fixes/6741-compression-preview-token-reconcile.md b/changelog.d/fixes/6741-compression-preview-token-reconcile.md deleted file mode 100644 index 122a3542655a..000000000000 --- a/changelog.d/fixes/6741-compression-preview-token-reconcile.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(compression):** `/api/compression/preview`'s top-level `originalTokens`/`compressedTokens` diverged from `engineBreakdown[0]`'s counts for the same single-engine run (tiktoken outer counts vs the `JSON.stringify(...).length/4` estimate per engine), worst on small inputs. A new `reconcileSingleEngineTokens()` overwrites the single-engine breakdown entry with the outer, more accurate figures; multi-step pipeline breakdowns are left untouched ([#6488](https://github.com/diegosouzapw/OmniRoute/issues/6488)). Regression guard: `tests/unit/compression/preview-outer-engine-token-reconcile-6488.test.ts`. diff --git a/changelog.d/fixes/6742-quota-preflight-coverage.md b/changelog.d/fixes/6742-quota-preflight-coverage.md deleted file mode 100644 index 45178354e4cc..000000000000 --- a/changelog.d/fixes/6742-quota-preflight-coverage.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(resilience):** account selection could pick an account already out of quota upstream on every credentialed route except `chat`/`codex` ([#6686](https://github.com/diegosouzapw/OmniRoute/issues/6686)) — `getProviderCredentials()` (`src/sse/services/auth.ts`) only skips a connection when a *local cache* already flags it exhausted (`isQuotaExhaustedForRequest`/`src/domain/quotaCache.ts`); it never itself calls the registered upstream `QuotaFetcher`. Only `getProviderCredentialsWithQuotaPreflight()` performs that live upstream check, and it was wired into exactly 2 call sites (`src/sse/handlers/chat.ts`, `src/app/api/internal/codex-responses-ws/route.ts`) — every other credentialed route (`rerank`, `images/generations`, `images/edits`, `audio/transcriptions|speech|translations`, `videos/generations`, `music/generations`, `ocr`, `providers/[provider]/embeddings`, `providers/[provider]/images/generations`, `web/fetch`, `moderations`, `search`) called the plain, cache-only selector, so an account whose cache entry was never populated (e.g. its first request landed on one of these routes) could be selected even at 0% quota remaining. Those 14 call sites now go through `getProviderCredentialsWithQuotaPreflight()` instead, matching chat/codex coverage. Regression guard: `tests/unit/issue-6686-quota-preflight-coverage.test.ts` (static check that none of the routes call the plain selector anymore + a behavioral check that the preflight-aware selector blocks a 100%-used account). diff --git a/changelog.d/fixes/6743-reasoning-content-web-sse.md b/changelog.d/fixes/6743-reasoning-content-web-sse.md deleted file mode 100644 index 089a53d9952e..000000000000 --- a/changelog.d/fixes/6743-reasoning-content-web-sse.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(api):** `reasoning_content` (extended-thinking text) was silently dropped from `/v1/chat/completions` SSE on the `claude-web` and `v0-vercel-web` executors ([#6662](https://github.com/diegosouzapw/OmniRoute/issues/6662)) — every chunk builder in both adapters hardcoded `delta: { content: ... }` with no reasoning path, unlike the established pattern already used by `default.ts`/`deepseek-web.ts`/`bedrock.ts` and the real-Anthropic-API `claude-to-openai.ts` translator (`thinking_delta` → `reasoning_content`). `v0-vercel-web.ts` now forwards an upstream `delta.reasoning_content` field (streaming and non-streaming) the same way `deepseek-web.ts` does. `claude-web.ts`'s `buildClaudeStreamingResponse` now maps a `content_block_start`(`type: "thinking"`)/`content_block_delta`(`delta.thinking`) pair onto `delta.reasoning_content`, and `claude-web/payload.ts`'s `transformToClaude()` no longer hardcodes `thinking_mode: "off"` — a new `wantsExtendedThinking()` derives it from the request's `reasoning_effort`/`reasoning.effort`/`thinking.type` signal, so extended thinking can actually be requested. Regression guard: `tests/unit/issue-6662-repro.test.ts` (RED→GREEN for both adapters). diff --git a/changelog.d/fixes/6757-rtk-enable-renderers-schema.md b/changelog.d/fixes/6757-rtk-enable-renderers-schema.md deleted file mode 100644 index a6aa1c910e58..000000000000 --- a/changelog.d/fixes/6757-rtk-enable-renderers-schema.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(api):** the compression config PUT schema now accepts `enableRenderers` for the RTK engine instead of rejecting the documented option (#6703, #6757 — thanks @alltomatos, with an independent duplicate fix from @chirag127 via #6756). diff --git a/changelog.d/fixes/6759-cookie-provider-apikey-cap.md b/changelog.d/fixes/6759-cookie-provider-apikey-cap.md deleted file mode 100644 index 56fa315e97fc..000000000000 --- a/changelog.d/fixes/6759-cookie-provider-apikey-cap.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(api):** raised the provider `apiKey` length cap for cookie-based web providers, whose session-cookie credentials legitimately exceed the previous limit (#6715, #6759 — thanks @alltomatos). diff --git a/changelog.d/fixes/6769-i18n-translate-pt-dashboard.md b/changelog.d/fixes/6769-i18n-translate-pt-dashboard.md deleted file mode 100644 index 590224dc7945..000000000000 --- a/changelog.d/fixes/6769-i18n-translate-pt-dashboard.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(i18n): translate hardcoded Portuguese dashboard strings to English (#6761, #6768)** (#6769 — thanks @chirag127). diff --git a/changelog.d/fixes/6780-bump-codex-client-version.md b/changelog.d/fixes/6780-bump-codex-client-version.md deleted file mode 100644 index 634ded640e5d..000000000000 --- a/changelog.d/fixes/6780-bump-codex-client-version.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(codex):** bump the default Codex CLI client identity from `0.142.0` to `0.144.0` for compatibility with newer Codex-backed models ([#6780](https://github.com/diegosouzapw/OmniRoute/pull/6780)) — thanks @quanturbo diff --git a/changelog.d/fixes/6788-tia-dashboard-loader.md b/changelog.d/fixes/6788-tia-dashboard-loader.md deleted file mode 100644 index 50e6f4f06b34..000000000000 --- a/changelog.d/fixes/6788-tia-dashboard-loader.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(ci):** the blocking "Impacted unit tests (TIA)" step false-redded any PR whose impact graph reached a dashboard component — it ran every selected test under `--import tsx/esm`, but `tests/unit/dashboard/**` requires the `--import tsx` CJS transform (ESM-only deep imports like `@lobehub/icons/es/*`), exactly as the canonical `test:unit:ci:shard` already does per segment. The impacted selection is now split by segment with matching loaders (closes #6787). diff --git a/changelog.d/fixes/6790-gemini-pdf-video-attachments.md b/changelog.d/fixes/6790-gemini-pdf-video-attachments.md deleted file mode 100644 index ad4cf383d96e..000000000000 --- a/changelog.d/fixes/6790-gemini-pdf-video-attachments.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(translator):** read PDF/video `file_data` attachments on the OpenAI→Gemini/Antigravity and OpenAI→Claude paths so multimodal documents (not just images) reach the upstream — PDFs map to `document`/`inlineData` and videos keep their `video/mp4` mime instead of being dropped (#6790 — thanks @Witroch4, with an independent report/fix from @samimozcan via #6762/#6753). diff --git a/changelog.d/fixes/6791-deepseek-web-done-after-finished.md b/changelog.d/fixes/6791-deepseek-web-done-after-finished.md deleted file mode 100644 index f7b161c4fd16..000000000000 --- a/changelog.d/fixes/6791-deepseek-web-done-after-finished.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(providers): ensure DeepSeek Web SSE emits [DONE] after FINISHED** (#6791 — thanks @Pitchfork-and-Torch). diff --git a/changelog.d/fixes/6792-compression-put-all-catalog-engines.md b/changelog.d/fixes/6792-compression-put-all-catalog-engines.md deleted file mode 100644 index 813620e098da..000000000000 --- a/changelog.d/fixes/6792-compression-put-all-catalog-engines.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(api):** the compression config `PUT` schema (`stackedPipelineStepSchema`) now accepts every `ENGINE_CATALOG` id — the structural engines `session-dedup`/`ccr`/`headroom`/`relevance`/`llmlingua`/`omniglyph` and the `aggressive` `ultra` intensity — so a `GET`→`PUT` round-trip of a stacked pipeline no longer 400s on a valid engine the discriminated union had omitted (#6747 — thanks @Pitchfork-and-Torch). diff --git a/changelog.d/fixes/6795-cursor-client-version-build-id.md b/changelog.d/fixes/6795-cursor-client-version-build-id.md deleted file mode 100644 index b82f2fbba215..000000000000 --- a/changelog.d/fixes/6795-cursor-client-version-build-id.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(cursor):** send the Agent CLI build id as `x-cursor-client-version` so Cursor upstream accepts requests from the current CLI build instead of a stale hardcoded version (#6795 — thanks @andrewmunsell). diff --git a/changelog.d/fixes/6805-strip-include-compact-responses.md b/changelog.d/fixes/6805-strip-include-compact-responses.md deleted file mode 100644 index 6c46a717a424..000000000000 --- a/changelog.d/fixes/6805-strip-include-compact-responses.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(codex): strip include from compact responses requests** (#6805 — thanks @yinaoxiong). diff --git a/changelog.d/fixes/6806-6806-claude-quota-data.md b/changelog.d/fixes/6806-6806-claude-quota-data.md deleted file mode 100644 index bbc9f7680327..000000000000 --- a/changelog.d/fixes/6806-6806-claude-quota-data.md +++ /dev/null @@ -1 +0,0 @@ -- fix(dashboard): surface Claude extraUsage credits in quota card when quotas is empty (#6806) diff --git a/changelog.d/fixes/6812-request-count-by-provider-date.md b/changelog.d/fixes/6812-request-count-by-provider-date.md deleted file mode 100644 index 503897954e61..000000000000 --- a/changelog.d/fixes/6812-request-count-by-provider-date.md +++ /dev/null @@ -1 +0,0 @@ -- **Request count by provider & date**: Dashboard → Analytics now shows a dedicated table of request counts grouped by provider and calendar date (plus token totals), for providers that bill per-request rather than per-token — sortable columns and a single-date filter. New `getProviderDailyUsageRows()` query (`src/lib/db/usageAnalytics.ts`) and its own `GET /api/usage/requests-by-provider-date` route (kept separate from the frozen `/api/usage/analytics` route). Regression guard: `tests/unit/db-provider-daily-usage-4009.test.ts`. (#4009 — thanks @tjengbudi) diff --git a/changelog.d/fixes/6817-ollama-cloud-weekly-quota.md b/changelog.d/fixes/6817-ollama-cloud-weekly-quota.md deleted file mode 100644 index 9ff2857cf520..000000000000 --- a/changelog.d/fixes/6817-ollama-cloud-weekly-quota.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(resilience):** an Ollama Cloud (or any apikey-category provider) account that hit a weekly usage cap kept getting retried every few minutes instead of backing off ([#3709](https://github.com/diegosouzapw/OmniRoute/issues/3709)) — the upstream 429 body ("you (\) have reached your weekly usage limit") was invisible to `checkFallbackError`'s existing subscription-quota-text classifier (Issue #2321) because that branch is gated by `shouldUseQuotaSignal`, which is oauth-only, so apikey providers like `ollama-cloud` fell through to the generic exponential backoff (~1s, capped at 2min) — one account took 285x429 in 48h. A new `isWeeklyUsageLimitText`/`buildWeeklyQuotaFallback` classifier (extracted, with the existing subscription-quota logic, into a new `open-sse/services/quotaTextCooldowns.ts` module so the frozen `accountFallback.ts` didn't have to grow) runs unconditionally and applies a 24h `QUOTA_EXHAUSTED` cooldown regardless of provider category. Regression guard: `tests/unit/ollama-cloud-weekly-quota-cooldown-3709.test.ts`. diff --git a/changelog.d/fixes/6821-budget-tokens-zero-gemini.md b/changelog.d/fixes/6821-budget-tokens-zero-gemini.md deleted file mode 100644 index 3886b4e6b3d3..000000000000 --- a/changelog.d/fixes/6821-budget-tokens-zero-gemini.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(providers):** an explicit `thinking.budget_tokens: 0` is now honored in the OpenAI→Gemini transform (thinking disabled) instead of being treated as unset (#6813, #6821 — thanks @alltomatos). diff --git a/changelog.d/fixes/6828-bootstrap-filter-empty-env.md b/changelog.d/fixes/6828-bootstrap-filter-empty-env.md deleted file mode 100644 index d4a6ca34ad52..000000000000 --- a/changelog.d/fixes/6828-bootstrap-filter-empty-env.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(bootstrap):** filter empty `process.env` values before spawning embedded services so a blank env var no longer crashes the Docker bootstrap in a restart loop (#6828 — thanks @AndrianBalanescu). diff --git a/changelog.d/fixes/6829-classify-404-model-not-found.md b/changelog.d/fixes/6829-classify-404-model-not-found.md deleted file mode 100644 index 77a741377c50..000000000000 --- a/changelog.d/fixes/6829-classify-404-model-not-found.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(providers):** classify upstream `404` responses as `MODEL_NOT_FOUND` (model lockout) instead of a retryable provider error, stopping the retry storm when a single model is missing (#6829 — thanks @AndrianBalanescu). diff --git a/changelog.d/fixes/6854-6854-mcp-toolcount.md b/changelog.d/fixes/6854-6854-mcp-toolcount.md deleted file mode 100644 index 1e0ac6b1fe7d..000000000000 --- a/changelog.d/fixes/6854-6854-mcp-toolcount.md +++ /dev/null @@ -1 +0,0 @@ -- fix(mcp): de-duplicate `TOTAL_MCP_TOOL_COUNT` by tool name instead of double-counting collections (#6854) diff --git a/changelog.d/fixes/6859-plugin-provider-id.md b/changelog.d/fixes/6859-plugin-provider-id.md deleted file mode 100644 index 9343798009ee..000000000000 --- a/changelog.d/fixes/6859-plugin-provider-id.md +++ /dev/null @@ -1 +0,0 @@ -- **fix(plugin):** the `@omniroute/opencode-plugin` dynamic provider hook stopped embedding its OC-1.17.8+-gate-compatible `opencode-`-prefixed provider id into model routing fields (`ModelV2.id`/`providerID`, combo catalog keys) — OmniRoute's server has no `opencode-` provider alias, so every dispatched model failed credential lookup with "No credentials for opencode-omniroute" (#6859). diff --git a/changelog.d/fixes/6876-6876-cliproxy-modelmap.md b/changelog.d/fixes/6876-6876-cliproxy-modelmap.md deleted file mode 100644 index d28d68467b4a..000000000000 --- a/changelog.d/fixes/6876-6876-cliproxy-modelmap.md +++ /dev/null @@ -1 +0,0 @@ -- fix(sse): apply cliproxyapiModelMapping at CLIProxyAPI dispatch time (#6876) diff --git a/changelog.d/maintenance/6784-merge-train.md b/changelog.d/maintenance/6784-merge-train.md deleted file mode 100644 index e98586183fae..000000000000 --- a/changelog.d/maintenance/6784-merge-train.md +++ /dev/null @@ -1 +0,0 @@ -- **Merge-train script** (`scripts/release/merge-train.sh`): batch-validates N queued PRs as ONE merged result on the runner box — merges every queued PR into a throwaway worktree cut from the release tip, runs the fast-gates parity suite once, and prints the `--admin` evidence block per PR (merge-gates §7). Replaces O(N²) per-PR CI re-runs in merge-storms. Regression guard: `tests/unit/merge-train-plan.test.ts`. diff --git a/changelog.d/maintenance/ci-vps-runner-sharding.md b/changelog.d/maintenance/ci-vps-runner-sharding.md deleted file mode 100644 index 925ce479a488..000000000000 --- a/changelog.d/maintenance/ci-vps-runner-sharding.md +++ /dev/null @@ -1 +0,0 @@ -- **ci:** unit fast-path sharding doubled 2→4 (halves the heaviest job's wall time) (#6781); the 3 heaviest fast-path jobs can route to the self-hosted VPS runner pool behind `USE_VPS_RUNNER` (#6691); `VPS_ALWAYS_ON` keeps the dedicated 24/7 CI host up across releases (teardown becomes a no-op) (#6693). diff --git a/changelog.d/maintenance/docs-strategy-count-skill-names.md b/changelog.d/maintenance/docs-strategy-count-skill-names.md deleted file mode 100644 index a14507159baa..000000000000 --- a/changelog.d/maintenance/docs-strategy-count-skill-names.md +++ /dev/null @@ -1 +0,0 @@ -- **docs:** routing-strategy count reconciled to 18 across AUTO-COMBO.md, README and AGENTS.md, and `p2c` casing fixed to match `ROUTING_STRATEGY_VALUES` (#6643, #6644, #6646 — thanks @chirag127); CLAUDE.md updated with the renamed review/triage/implement skill-family names (#6663). diff --git a/changelog.d/maintenance/readme-strategy-tool-counts.md b/changelog.d/maintenance/readme-strategy-tool-counts.md deleted file mode 100644 index 6e82bd00c112..000000000000 --- a/changelog.d/maintenance/readme-strategy-tool-counts.md +++ /dev/null @@ -1 +0,0 @@ -- **docs(readme):** fix stale counts — 18 routing strategies (adds the missing `pipeline` row), 94 MCP tools, 12-factor Auto-Combo scoring. diff --git a/changelog.d/maintenance/release-v3.8.47-basereds.md b/changelog.d/maintenance/release-v3.8.47-basereds.md deleted file mode 100644 index 5305f83ac726..000000000000 --- a/changelog.d/maintenance/release-v3.8.47-basereds.md +++ /dev/null @@ -1 +0,0 @@ -- **chore(ci):** fix two shared base-reds on the release tip that blocked the PR queue — register `cliproxyapi-model-mapping-dispatch.test.ts` in `stryker.conf.json` `tap.testFiles` (mutation-coverage gap left by #6903) and update `provider-models-route-codex.test.ts` to expect Codex client version `0.144.0` (stale assertion left by #6780's production bump). diff --git a/changelog.d/maintenance/root-cleanup-llmtxt-design-system.md b/changelog.d/maintenance/root-cleanup-llmtxt-design-system.md deleted file mode 100644 index acaad759f669..000000000000 --- a/changelog.d/maintenance/root-cleanup-llmtxt-design-system.md +++ /dev/null @@ -1 +0,0 @@ -- **docs:** refresh `llm.txt` to the current project state (248 providers, 94 MCP tools / 30 scopes, 18 routing strategies, 12-factor Auto-Combo scoring, v3.8.47) and sync its 42 i18n mirrors; move the implemented design-system plan from the repo root to `docs/architecture/DESIGN_SYSTEM.md` rewritten as a reference doc.