Repository navigation
Release v3.8.26 - #3875
Release v3.8.26#3875
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Code Review
This pull request bumps the project version from 3.8.25 to 3.8.26 across multiple package files, lockfiles, OpenAPI specifications, and localized changelogs. It also documents a CI fix in the main CHANGELOG regarding granting write permissions to the npm publish job for SBOM attachment. I have no feedback to provide as there are no review comments.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
CI Coverage Report
Coverage artifact was not available for this run. |
…d docs audit report - README advertised a stale '177 providers'; the canonical generator (gen-provider-reference.ts) reports 226 unique provider IDs. Updated the README badges/anchors/heading and regenerated docs/reference/PROVIDER_REFERENCE.md (223→226) to match the source of truth. - Adds DOCUMENTATION_AUDIT_REPORT.md (docs/i18n sync audit + plan). Docs-only; carried over from in-progress working-tree changes and verified against the generator.
…3894) Document the real pipeline (Session-Dedup, CCR, RTK, Headroom, Caveman, LLMLingua-2, Lite, Aggressive, Ultra) that replaced the old RTK+Caveman framing; presets table kept. '7 options' -> '9 engines'.
…root (#3896) Move the committed quality-gate state files out of the repo root into config/quality/ and the v3.8.24 documentation audit into docs/ops/, then re-point every gate script, test and .gitignore entry at the new paths. Refresh docs/architecture/REPOSITORY_MAP.md (stale since v3.8.2) to match the current layout. Moved -> config/quality/: quality-baseline.json, complexity-baseline.json, duplication-baseline.json, file-size-baseline.json, test-discovery-baseline.json, dependency-allowlist.json, .license-allowlist.json (generated quality-metrics.json now written here too; still gitignored) Moved -> docs/ops/: DOCUMENTATION_AUDIT_REPORT.md (+ meta.json entry + fabricated-docs skip) Path updates: check-{complexity,duplication,file-size,test-discovery,deps, licenses,dead-code,cognitive-complexity,type-coverage}.mjs, check-quality- ratchet.mjs, collect-metrics.mjs, check-tracked-artifacts.mjs (+ its test and check-deps test). Also gitignore /logs/ (was untracked-not-ignored). Tracked root files: 56 -> 48. Tool configs left in root on purpose: most are auto-discovered there, and the tsconfig variants have location-relative files:[] arrays that would need 46 path rewrites for a 2-file gain.
#3900) The wiki has no native generator and drifts each release — it lacked SUPPLY_CHAIN plus 24 other docs pages, and the cover counts went stale (212+/14/37 vs 226/15/87). Adds: - scripts/docs/sync-wiki.mjs — adds docs/ pages missing from the wiki (curated; internal reports/plans/index excluded) and syncs the four Home.md cover counts. Matches the hand-curated, non-deterministic wiki page names by a normalized fuzzy key and writes the EXISTING name, so it never creates duplicate pages. Overwriting existing-page content is opt-in (--update-existing) and intentionally OFF by default: several docs sources still carry stale counts (e.g. ARCHITECTURE.md says "177 providers / 37 MCP tools" while the wiki cover is 226/87), so a blind overwrite would REGRESS the wiki. Full parity is gated on regenerating those sources — see docs/ops/DOCUMENTATION_AUDIT_REPORT.md. - .github/workflows/wiki-sync.yml — runs the sync on every push to main that touches docs/ (or a count source) + workflow_dispatch, pushing via GITHUB_TOKEN. - tests/unit/sync-wiki.test.ts — pure-function coverage (8 tests). The first run already pushed the 25 missing pages to the wiki.
Integrated into release/v3.8.26
Integrated into release/v3.8.26
Integrated into release/v3.8.26
Integrated into release/v3.8.26
…sing (#3887) Integrated into release/v3.8.26
Integrated into release/v3.8.26
…3883) Integrated into release/v3.8.26 (scoped to the ESM-only loader fix)
…ocs build passes docs/ops/DOCUMENTATION_AUDIT_REPORT.md (added in #3804) was the only file under docs/ops/ without a `title:` frontmatter block. Fumadocs scans docs/** into the `docs` collection and fails the production build with "Invalid input: expected string, received undefined" (title) — the same MDX frontmatter class of break as the v3.8.25 SUPPLY_CHAIN.md incident (#3864). Fast Quality Gates does not run `npm run build`, so it stayed green on the release branch and would only explode at release->main sync. Added the frontmatter matching the sibling docs/ops/*.md convention; full build now passes (Next.js compiled 549/549 pages).
…ols / 15 strategies / 42 locales) (#3904) Several docs bodies carried stale counts from the v3.8.0–v3.8.2 era while the code moved on. Brought them to the canonical values verified against source: - providers 177/160+/223 → 226 (docs/reference/PROVIDER_REFERENCE.md "Total providers") - MCP tools 37/42/43 → 87 (open-sse/mcp-server TOTAL_MCP_TOOL_COUNT) - routing strategies 14 → 15 (routingStrategies.ts ROUTING_STRATEGY_VALUES) - i18n locales 40/40+ → 42 (config/i18n.json) - MCP scopes ~13/13 → 30 Files: ARCHITECTURE, CODEBASE_DOCUMENTATION, REPOSITORY_MAP, QUALITY_GATES, ACP, AGENT-SKILLS, AGENTBRIDGE, PROVIDERS-GUIDE, SETUP_GUIDE, MCP-SERVER (headline), OMNIROUTE_VS_ALTERNATIVES, README, RELEASE_CHECKLIST. Executors (60), OAuth providers (16), A2A skills (6) and cloud agents (3) were already correct (check-docs-counts-sync --strict still passes). Left untouched on purpose: the point-in-time reports (DOCUMENTATION_AUDIT_REPORT, E2E shakedown) and the MCP tool inventory diagram (mcp-tools-43.svg) — diagram regeneration is a separate task. This unblocks full GitHub-wiki content parity: the wiki was synced from these corrected sources via scripts/docs/sync-wiki.mjs --update-existing.
Integrated into release/v3.8.26
…inned proxy is unreachable (#3906) Integrated into release/v3.8.26
…efault keepAlive (#3907) Integrated into release/v3.8.26 (zai validator; global keepAlive change reverted on review)
…ilure on push) (#3892) Integrated into release/v3.8.26
…eset (#3893) Integrated into release/v3.8.26
…3 follow-up) (#3899) Integrated into release/v3.8.26
… (advisory) (#3901) Integrated into release/v3.8.26
…7 Task 11) (#3898) Integrated into release/v3.8.26
…ld (#3902) Integrated into release/v3.8.26
…ls (#3909) * docs(mcp): correct the MCP tool-inventory diagram source + text to 87 tools The mcp-tools diagram source was frozen at v3.8.8 (43 tools = 30 core + 3 memory + 4 skills + 6 notion) — missing the agent-skills, gamification, plugins and obsidian modules, and Core had grown 30 → 33. Corrected to the real breakdown verified against open-sse/mcp-server (TOTAL_MCP_TOOL_COUNT): 33 core + 3 memory + 4 skills + 3 agent-skills + 8 gamification + 8 plugins + 6 notion + 22 obsidian = 87 - renamed mcp-tools-43.{mmd,svg} → mcp-tools-87.{mmd,svg} - rewrote the .mmd source with the 8 real categories - fixed MCP-SERVER.md: source-of-truth line, image alt, and the inventory caption - fixed docs/diagrams/README.md index entry check:doc-links PASS (links resolve).⚠️ The committed mcp-tools-87.svg is the OLD render (still draws 43 tools): the SVG must be regenerated with `npm run docs:render-diagrams` in an environment with a working headless Chromium. It could NOT be rendered in this sandbox — Chromium is missing system libraries (libnss3 / libatk / libcups / libxcb, no apt access). The .mmd source and all surrounding text are correct, so a single render call finalizes the image. * docs(mcp): render mcp-tools-87.svg (87-tool inventory diagram)
…#3804) Integrated into release/v3.8.26 — reconciled: kept #3900's superset wiki-sync, dropped the superseded sync-wiki-home; counts taken from the newer canonical release docs; net-new value = vale/markdownlint docs-lint infra + 7 new docs (Notion/Obsidian/Plugin-Marketplace/Cost-Tracking/Free-Provider-Rankings/Feature-Flags/Egress-Policy) + check-docs-counts-sync guard.
… source revert (#3933) PR #3907 lowered the test assertions for fetchKeepAliveTimeoutMs from 4000 to 1000 expecting DEFAULT_FETCH_KEEPALIVE_TIMEOUT_MS to drop to 1000, but the source change was reverted on review (kept at 4000, with keepAliveMaxTimeout pinning instead). The test was left asserting 1000, turning the unit suite red release-wide. Align the assertions back to the shipped source value (4000).
… works (#3922) Integrated into release/v3.8.26
…(Hard Rule #19) (#3939) Multiple sessions/agents share the main checkout, so a git checkout/branch switch there silently discards another session's uncommitted work. Document the worktree- isolation workflow (ask the operator for the base branch first, cut a dedicated worktree+branch off it, tear down only your own) as a new 'Worktree isolation' subsection under Git Workflow, and codify it as Hard Rule #19.
Integrated into release/v3.8.26 — mid-stream failure persistence (follow-up to #3879). Validated locally: typecheck:core clean, 75/75 stream/usage tests, eslint 0 errors, file-size + any-budget OK.
…TP 400 (#3938) Integrated into release/v3.8.26 — Perplexity-web schema v2.18 payload fix for HTTP 400. Validated: 24/24 perplexity tests, typecheck:core clean, file-size rebaselined (perplexity-web.ts 868->939, justified).
Integrated into release/v3.8.26 — keep pendingById in sync with the queue detail (Object.assign in place). Validated alongside #3937: typecheck:core clean, 42/42 request-logger + lifecycle tests, eslint 0 errors, file-size OK.
…lerts to blocking (#3945) FIX 1 — security scanner install (gitleaks/osv/actionlint/zizmor): the step ran under bash -e and aborted before the $GITHUB_PATH export when 'go install ...gitleaks/v8@latest' failed/produced a non-working binary, so no scanner landed on PATH and every check self-skipped. Rewritten to set +e, install from official release downloads, ALWAYS export $HOME/.local/bin, and print diagnostics. Validated only on the next CI run (binaries install in CI). FIX 2 — size-limit bundleSize: add @size-limit/file devDependency (the correct preset for the plain FILE-size .size-limit.json) + allowlist entry. check:bundle-size now measures the 4 bin entries via the preset (bundleSize=5601) instead of erroring on the missing preset / falling back to fs.statSync. FIX 3 — codeqlAlerts promoted to BLOCKING: check-codeql-ratchet.mjs now reads metrics.codeqlAlerts.value, exits 1 ONLY on a real regression (measured > baseline), and exits 0 (graceful skip) on any measurement failure (gh absent / no auth / no repo / API error) so missing infra never blocks. Baseline seeded codeqlAlerts=0 (repo has 0 open alerts). Blocking step wired in the quality-gate job with security-events:read; the duplicate advisory step removed from quality-extended. New TDD: evaluateCodeqlRatchet (5 cases).
…visory baselines (#3947) Three CI security gates in the quality-extended job never produced a value; diagnose + fix each, then freeze the real measured numbers as advisory ratchet baselines (dedicatedGate => SKIP in the blocking quality-gate ratchet). FIX 1 — .zizmor.yml: migrate the config from the pre-1.0 'ignores: []' schema to the 'rules: {}' schema. zizmor 1.25.2 rejected the old field ('unknown field `ignores`, expected `rules`') and performed NO audit. Now check:workflows emits zizmorFindings=195. FIX 2 — scripts/check/check-secrets.mjs: the gate ran 'gitleaks detect --no-git --source .', which walks the WHOLE tree including a real node_modules/ (90k+ files under npm ci) and times out (ETIMEDOUT) — gitleaks has no traversal-exclude flag (.gitleaks.toml paths filter findings AFTER reading). Scope the scan to the source dirs (src/open-sse/bin/electron/scripts), one 'gitleaks dir <dir>' invocation each ('gitleaks dir' takes a single path; multiple args fall back to scanning the CWD). Also fix .gitleaks.toml: it lacked [extend].useDefault=true, so the custom config REPLACED the default ruleset with zero rules and detected nothing — the gate always reported 0 regardless of real secrets. Now: ~10s (was 120s timeout), secretFindings=3 (generic-api-key false positives in beta-header strings / column names). FIX 3 — .github/workflows/ci.yml: the scanner install resolved release URLs via unauthenticated api.github.com (60 req/hr/IP; returns empty when throttled -> silent no-op install -> every gate self-skips). Switch gitleaks + osv-scanner to 'gh release download' (preinstalled + GITHUB_TOKEN-authed, 5000 req/hr); add GH_TOKEN to the step env. actionlint/zizmor install paths unchanged. MEASURE + FREEZE (advisory, dedicatedGate:true, direction down) in config/quality/quality-baseline.json: secretFindings=3, zizmorFindings=195, vulnCount=13 (LOW=4/MOD=7/HIGH=2), bundleSize=5601. Seeded from a local run with the real binaries on PATH (2026-06-15). They stay advisory (SKIP in the blocking ratchet; quality-extended is continue-on-error) until a green CI run confirms the fixed tooling produces values; the flip to blocking is a follow-up PR. continue-on-error untouched. Validated locally: zizmor --config parses; check:secrets <60s + real count; check:workflows/check:vuln-ratchet emit real numbers; ci.yml actionlint-clean; baseline JSON valid; 103 build-scanner unit tests + 19 check-secrets + 18 quality-ratchet pass; the 4 keys SKIP in the ratchet. FIX 3 logic is sound but CI-only (cannot run gh release download against the runner locally).
…plate-injection + allowlist guarded workflow_run (#3949) Remediate the real findings the now-functional osv-scanner and zizmor gates surfaced on release/v3.8.26. Deps (osv-scanner, 2 HIGH -> 0): - form-data 4.0.5 -> ^4.0.6 (GHSA-hmw2-7cc7-3qxx, transitive via axios) - vite 8.0.5 -> ^8.0.16 (GHSA-fx2h-pf6j-xcff HIGH + GHSA-v6wh-96g9-6wx3 MODERATE; dev-only via vitest/@vitejs/plugin-react/fumadocs-mdx) Applied via package.json overrides of existing deps (no new allowlist entry needed). vulnCount 13 -> 10; build:cli + vitest MCP suite (16 files/187 tests) green post-bump. Workflows (zizmor, 195 -> 187): - env-harden 7 template-injection findings by moving each ${{ ... }} into env: and referencing "$VAR" in the script (GitHub-documented mitigation): ci.yml i18n; electron-release.yml validate/build/release steps. - allowlist 1 dangerous-triggers FP: deploy-vps.yml on:workflow_run is guarded on conclusion=='success' and deploys via SSH without checking out untrusted code. Added .zizmor.yml rules.dangerous-triggers.ignore with justification. Tighten baselines to the improved state (direction: down): vulnCount 13 -> 10, zizmorFindings 195 -> 187. secretFindings (3) and bundleSize (5601) unchanged.
) New advisory gate (Fase 8 B.4) that diffs the public API contract docs/reference/openapi.yaml against the base branch via oasdiff, surfacing removed endpoints, newly-required params, removed response fields, etc. - scripts/check/check-openapi-breaking.mjs: resolves base spec via git show <BASE_REF>:docs/reference/openapi.yaml to a temp file, runs oasdiff breaking --format json, parses+counts breaking changes, emits openapiBreaking=N (KEY=VALUE for collect-metrics). ADVISORY: exit 0 always; graceful SKIP when oasdiff is absent or the base spec can't be resolved. - package.json: check:openapi-breaking script. - .github/workflows/ci.yml (quality-extended, advisory): install oasdiff via gh release download, add the breaking-change step (BASE_REF via env, never shell-interpolated), fetch-depth: 0 so git show can read the base spec. - tests/unit/build/check-openapi-breaking.test.ts: parser counting/grouping + binary-absent SKIP integration. - docs/architecture/QUALITY_GATES.md: document the quality-extended job table. - docs/reference/openapi.yaml: define the BadRequest/NotFound/InternalError response components that were referenced (14 call sites) but never defined — a pre-existing dangling-$ref defect that blocked oasdiff from loading the spec. No path behavior changes; purely additive to components.responses.
…alog regression, sync i18n - Reconcile the [3.8.26] CHANGELOG to cover all 43 commits since v3.8.25; move 3 bullets (#3877/#3881/#3890) that were misfiled under [3.8.25] after the tag back into [3.8.26], restoring [3.8.25] to its published/tagged state. - fix(providers): keep the /v1/models catalog alias-only. #3870 made generateModels() mirror models under each raw provider id, surfacing phantom opencode/* entries that collide with the opencode/ -> opencode-zen route (regression vs v3.8.25, caught by the #2798 catalog regression test). getProviderModels() now resolves raw id -> alias at lookup time instead, preserving #3870's intent (getProviderModels("github") == the "gh" alias) without polluting the public model namespace. - Inject the full EN [3.8.26] section into the 41 i18n CHANGELOG mirrors (docs-sync body-size). - Allowlist BASE_REF in check-env-doc-sync (CI-only var for the OpenAPI breaking-change gate).
# Conflicts: # electron/package-lock.json
|
OmniRoute v3.8.26 — see CHANGELOG.md [3.8.26] for the full notes. Highlights: Vertex AI media generation (cheaper-inference#3929), GLM-5.2 effort-tier routing (cheaper-inference#3885), sticky round-robin combos (cheaper-inference#3846), OpenRouter connection presets (cheaper-inference#3878), compression prompt-cache fix (cheaper-inference#3936/cheaper-inference#3890), and a security pass (form-data/vite + workflow hardening, cheaper-inference#3949). Co-authored-by: artickc <artickc@users.noreply.github.com> Co-authored-by: rdself <rdself@users.noreply.github.com> Co-authored-by: herjarsa <herjarsa@users.noreply.github.com> Co-authored-by: Jack Smith <16862258+YunyunZhai@users.noreply.github.com> Co-authored-by: dhaern <dhaern@users.noreply.github.com> Co-authored-by: adivekar-utexas <adivekar-utexas@users.noreply.github.com> Co-authored-by: megamen32 <megamen32@users.noreply.github.com> Co-authored-by: zhiru <zhiru@users.noreply.github.com> Co-authored-by: insoln <insoln@users.noreply.github.com> Co-authored-by: diego-anselmo <diego-anselmo@users.noreply.github.com>
OmniRoute v3.8.26 — see CHANGELOG.md [3.8.26] for the full notes. Highlights: Vertex AI media generation (cheaper-inference#3929), GLM-5.2 effort-tier routing (cheaper-inference#3885), sticky round-robin combos (cheaper-inference#3846), OpenRouter connection presets (cheaper-inference#3878), compression prompt-cache fix (cheaper-inference#3936/cheaper-inference#3890), and a security pass (form-data/vite + workflow hardening, cheaper-inference#3949). Co-authored-by: artickc <artickc@users.noreply.github.com> Co-authored-by: rdself <rdself@users.noreply.github.com> Co-authored-by: herjarsa <herjarsa@users.noreply.github.com> Co-authored-by: Jack Smith <16862258+YunyunZhai@users.noreply.github.com> Co-authored-by: dhaern <dhaern@users.noreply.github.com> Co-authored-by: adivekar-utexas <adivekar-utexas@users.noreply.github.com> Co-authored-by: megamen32 <megamen32@users.noreply.github.com> Co-authored-by: zhiru <zhiru@users.noreply.github.com> Co-authored-by: insoln <insoln@users.noreply.github.com> Co-authored-by: diego-anselmo <diego-anselmo@users.noreply.github.com>
OmniRoute v3.8.26 — see CHANGELOG.md [3.8.26] for the full notes. Highlights: Vertex AI media generation (cheaper-inference#3929), GLM-5.2 effort-tier routing (cheaper-inference#3885), sticky round-robin combos (cheaper-inference#3846), OpenRouter connection presets (cheaper-inference#3878), compression prompt-cache fix (cheaper-inference#3936/cheaper-inference#3890), and a security pass (form-data/vite + workflow hardening, cheaper-inference#3949). Co-authored-by: artickc <artickc@users.noreply.github.com> Co-authored-by: rdself <rdself@users.noreply.github.com> Co-authored-by: herjarsa <herjarsa@users.noreply.github.com> Co-authored-by: Jack Smith <16862258+YunyunZhai@users.noreply.github.com> Co-authored-by: dhaern <dhaern@users.noreply.github.com> Co-authored-by: adivekar-utexas <adivekar-utexas@users.noreply.github.com> Co-authored-by: megamen32 <megamen32@users.noreply.github.com> Co-authored-by: zhiru <zhiru@users.noreply.github.com> Co-authored-by: insoln <insoln@users.noreply.github.com> Co-authored-by: diego-anselmo <diego-anselmo@users.noreply.github.com>




Release v3.8.26 —
release/v3.8.26→main. Final release notes (reconciled at release time).[3.8.26] — 2026-06-15
✨ New Features
stickyRoundRobinLimit), balancing stickiness against spread. (#3846 — thanks @adivekar-utexas)🐛 Fixed
cache_controlbreakpoints, keeping the cacheable prefix (system prompt + prior turns) byte-stable. (2) the cache-awareskipSystemPromptflag computed bygetCacheAwareStrategy()was dropped byselectCompressionStrategy()(which can only return a mode), so the system prompt could still be compressed under caching; a newresolveCacheAwareConfig()now forcespreserveSystemPrompton for caching requests. (#3936, closes #3890 — thanks @xenstar / @diegosouzapw)ark-…) key reported "invalid".bytepluswas present in the provider catalog (APIKEY_PROVIDERS) but never registered in the routing registry, so key validation fell through to{ unsupported: true }→ HTTP 400 → the UI rendered every key as invalid (and the provider was unusable for inference). Added a registry entry modeled on the existing Volcengine Ark provider: OpenAI-compatible format, basehttps://ark.ap-southeast.bytepluses.com/api/v3(regionap-southeast-1),Authorization: Bearerauth, seeded with the catalog's advertised models (Seed 2.0, Kimi K2 Thinking, GLM 4.7, GPT-OSS-120B). (#3935, closes #3877 — thanks @nikohd12 / @diegosouzapw)curl. The validation probe sentmodel: "nousresearch/hermes-4-70b", which Nous does not serve, so the API returned400and the validator (which only treated200/429as success) reported the key invalid. The probe now uses the realHermes-4-70Bslug, and any non-auth 4xx (400/404/422) is treated as a valid key (the request shape was wrong, not the credentials) — mirroring the longcat/nvidia validators so a future model rename can't re-break key validation. (#3934, closes #3881 — thanks @FerLuisxd / @diegosouzapw)streamFailureFinalizationpath and merges incremental Claude usage (follow-up to fix: stabilize reasoning streams and request logs #3879). (#3937 — thanks @rdself)Object.assign) so the in-flight payload stays consistent with what was dispatched (coexists with fix(stream): persist mid-stream failures #3937). (#3940 — thanks @rdself)role: "assistant", which strict OpenAI-compatible clients expect before content deltas. (#3911 — thanks @diego-anselmo)generative-languageOAuth scope; the scope is now requested. (#3922 — thanks @artickc)node:sqlitewhen the better-sqlite3 binding is missing — the MCP server now falls back to Node's built-innode:sqlitewhen the native better-sqlite3 binding is unavailable, instead of crashing. (#3887 — thanks @megamen32)🔒 Security & Hardening
workflow_run— two HIGH Dependabot advisories (form-data,vite) were upgraded; GitHub Actions workflows were hardened against${{ }}template-injection (untrusted values now passed viaenv:); and the guardedworkflow_runtrigger was allowlisted. (#3949 — thanks @diegosouzapw)🧹 Internal / Quality / Docs
contents: writeto the npm publish job for SBOM attach — the v3.8.25 TokenPermissions hardening set the npm-publishpublishjob tocontents: read, but its "Attach SBOM to GitHub Release" step (gh release upload) needscontents: writeand failed with HTTP 403 on the v3.8.25 release (npm / GitHub Packages / opencode-plugin / Docker / Electron all published fine; only the SBOM attach broke — the v3.8.25 SBOM was attached manually). (#3874 — thanks @diegosouzapw)/v1/modelscatalog alias-only (release-time follow-up to Fix/generate models alias lookup #3870) — Fix/generate models alias lookup #3870 madegenerateModels()also key the registry by each provider's raw id, which surfaced phantomopencode/*entries in/v1/modelsthat collide with theopencode/→ opencode-zen route (a regression vs v3.8.25, caught by the [BUG] Models from "OpenCode Free" provider are active in UI but return an empty list in /v1/models #2798 catalog regression test).getProviderModels()now resolves a raw provider id to its alias at lookup time instead of mirroring raw-id keys into the model namespace, preserving Fix/generate models alias lookup #3870's intent (getProviderModels("github")returns the same models as theghalias) without polluting the public catalog. (#3870 — thanks @diegosouzapw / @YunyunZhai)codeqlAlertsto blocking — corrected the scanner install and the size-limit preset, and promoted thecodeqlAlertsratchet from advisory to blocking. (#3945 — thanks @diegosouzapw)$refs — a CI gate diffs the OpenAPI spec against the base branch (BASE_REF) with oasdiff to surface breaking API changes, and the spec's dangling$refs were repaired. (#3951 — thanks @diegosouzapw)check-known-symbols— stale allowlist entries (suppressing a symbol that no longer exists) now fail the gate — Fase 6A.3 follow-up. (#3899 — thanks @diegosouzapw)secrets-in-job-iffrom nightly-llm-security — referencingsecretsin a job-levelifcaused astartup_failureon push; the gating was moved so the workflow starts cleanly. (#3892 — thanks @diegosouzapw)config/quality, declutter the repo root — baselines / allowlists / metrics moved underconfig/quality/, trimming the tracked root file count. (#3896 — thanks @diegosouzapw)PROVIDER_REFERENCE.md— the README advertised a stale177 providers; the canonical generator (scripts/docs/gen-provider-reference.ts) now reports 226 unique provider IDs, so the README badges/anchors and the generated provider reference were brought in sync. Also adds a documentation audit/sync report. (thanks @diegosouzapw)DOCUMENTATION_AUDIT_REPORTso the fumadocs build passes — the audit report lacked thetitle:frontmatter MDX pages require. (thanks @diegosouzapw)[3.8.25] — 2026-06-14
✨ New Features
ListAvailableModels(region-matched, with a static-catalog fallback). (#3836 — thanks @artickc)predictLongRunning) now appear in Gemini/Vertex dynamic model discovery. (#3839 — thanks @artickc)runWithProxyContext), with a "Distribute proxies" UI helper. (#3837 — thanks @pizzav-xyz)ARENA_ELO_SYNC_ENABLED, DB-override + env fallback). (#3821 — thanks @rdself)🐛 Fixed
tokenUrlpath, so the fix was never proven for the actual Google-family providers, which dispatch throughrefreshGoogleToken()against the hardcodedOAUTH_ENDPOINTS.google.token. Added a test that drivescheckConnectionthrough the realgemini-cli/antigravitypath (redirecting the Google token endpoint to a local server returninginvalid_grant) and asserts therefresh_tokenis preserved (not nulled) — confirming these connections are not spuriously destroyed on a failed refresh. (#3850 — thanks @3xa228148)Internal server errorat the Add Connection step.buildAuthUrlthrew whenGITLAB_DUO_OAUTH_CLIENT_IDwas missing, and the route swallowed it into a generic 500. It now returnsnull(mirroring the Qoder provider) and the authorize route surfaces an actionable message: register an OAuth app athttps://gitlab.com/-/profile/applicationswith redirect URIhttp://localhost:20128/callbackand scopesai_features read_user, then setGITLAB_DUO_OAUTH_CLIENT_ID. (#3861 — thanks @sidinsearch).envpost-start was ignored too, sinceprocess.envisn't reloaded).getDbBackupMaxFiles()only read theDB_BACKUP_MAX_FILESenv var — there was no setter and no persisted value. The value now round-trips through a dedicatedkey_valuestore (getDbBackupMaxFilesprecedence: env override → persisted UI value → default 20), and the "Clean old backups" action persists the chosen count. Existing installs keep the historical default of 20 until explicitly changed. (#3834 — thanks @netstratego)reasoning_effort/effort=high400) — translating OpenAIreasoning_effort=high(and Claude-Codeoutput_config.effort=high) to a Gemini target sent a hardcodedthinkingBudget: 32768, which exceeds Flash-tier Gemini's real max of 24576 → upstream HTTP 400 (thethinkingLevel=highpath already used 24576 and worked on the same model).gemini-2.5-flashnow declares its realthinkingBudgetCap(24576) so the existingcapThinkingBudget()chokepoint actually clamps, and the Claude→Geminioutput_config.effortpath — which previously sent the raw value with no cap at all — now routes through the same clamp (pro-tier, real cap 32768, is left untouched). (#3842 — thanks @andrea-kingautomation)PRICING_SYNC_ENABLED) and the models.dev capability sync (Settings → AI toggle) were only initialized fromserver-init.ts, which the Next standalone runtime never executes — and models.dev had no caller at all. Their toggles were inert in production. Both are now initialized frominstrumentation-node.ts(self-gated, opt-in preserved, non-blocking, never fatal). (thanks @diegosouzapw)proxyEnabled: false) already overrides a configured global proxy (resolveProxyForConnectionshort-circuits tolevel: "direct"before the global step). Added an explicit regression test proving the bypass beats a global assignment (and round-trips on re-enable), and relabeled the UI to "Direct (bypass proxy)" so operators recognize it. Closes the verification gap in #2996. (thanks @diegosouzapw)providerSpecificData.disableCooling, with a toggle in the Edit Connection modal). When set, a recoverable failure still records the error/backoff but does not take the connection out of rotation, so it stays eligible for selection — useful for a primary key you never want parked on a blip. Terminal states (banned / expired / credits_exhausted) still apply. (#2997 — thanks @diegosouzapw)<omniModel>-tag combo pinning with a server-side context-cache pin gated on a clientsessionId. Clients that send no session id (most OpenAI-compatible tools) lost combo stickiness, so combos re-ran strategy selection every turn → upstream prompt-cache misses → cold high-reasoning starts (~78s) → intermittent[504] Upstream request did not return response headers+ TPS collapse (only on combos). The pin now falls back to a stable per-conversation fingerprint (extractSessionAffinityKey(body)) when no session id is present — only whencontext_cache_protectionis on, so fix: server-side context cache pinning, stop proxy message leaks, persist context_cache_protection toggle #3399's anti-leak behaviour is preserved. Separately, the stream-readiness window now grants the +30s reasoning budget unconditionally for high-reasoning Codex GPT-5.x (small high-reasoning prompts were 504-ing at the 80s base regardless of stickiness). (#3825 — thanks @bypanghu)skipProviderBreakerconsumer gate — the producer was tested but the consumer (whether a failed combo target trips the whole-provider circuit breaker) was not; the breaker decision is now an exported pure predicate (shouldRecordProviderBreakerFailure, behaviour-identical) with direct tests asserting aconnection_cooldown503 does not trip the breaker while a plain 503 does. Closes another deferred test gap from #2743. (thanks @diegosouzapw)choices) is now propagated with its sanitized message. The Windsurf "Visit windsurf.com/show-auth-token" instruction (the bare URL shows no token without an IDE-supplied?state=) now directs users to theWindsurf: Provide Auth Tokencommand-palette flow. (#3324 — thanks @mikmaneggahommie)50. The threshold is now configurable viaOMNIROUTE_MAX_PENDING_MIGRATIONS(resolved at startup;0disables the check). (#3416 — thanks @samuraiIT)proxyFetchpath — net-new tests forbuildVercelRelayHeadersand thevercel-type relay short-circuit (x-relay-target/-path/-auth, TCP-skip, missing-auth fail-closed), closing one of the deferred test gaps tracked in #2743. (thanks @diegosouzapw)omniroute runtime repairin the native-module error messages — after a Node major upgrade,better-sqlite3's prebuilt binary mismatches the ABI and the service can crash-loop; the error only mentionednpm rebuild better-sqlite3(which fails for global / no-toolchain installs). The startup + SQLite error hints now also point to the existing self-heal commandomniroute runtime repair(rebuilds into a user-writable runtime), and a top-levelomniroute repairalias was added. (#3476 — thanks @Rahulsharma0810)gemini-3.1-pro-high400) — Antigravity silently renamed the Gemini 3.1 Pro-high upstream id, sogemini-3.1-pro-highstarted returning HTTP 400 (while-lowstill worked) and the live id can't be determined statically (competitor proxies disagree). The executor now retries alternative ids on a 400 (gemini-3.1-pro-high→gemini-pro-agent→gemini-3-pro-high, analogous for pro-low), bounded and only on a 400, with zero extra cost on the happy path; the 1:1 tier-passthrough invariant is preserved (the chain is request-time, not a static alias remap). (#3786 — thanks @aliaksandrsen)STREAM_EARLY_EOF) for single-model requests — flaky OpenAI-compatible upstreams (e.g. NVIDIA NIM with minimax-m3 / qwen3.5 / glm-5.1) intermittently send HTTP 200 then close the SSE with zero useful frames, surfacing as a 502 "Stream ended before producing useful content". Only Antigravity got an early-close retry; every other provider returned the 502 immediately on the non-combo single-model path. A bounded one-retry (early-close only — not readiness-timeout — and without marking the account unavailable) now generalizes it. (The separate qwen-web validation SSRF part of the same report was already fixed in v3.8.24, #3767.) (#3758 — thanks @Svatosalav)isDeletedmarker now separates the trash/delete path (still dropped on re-import, [BUG] model cannot delete in llamacpp #3199) from the eye toggle (preserved as listed-but-hidden), and eye-hidden models are no longer re-aliased into the routable catalog on sync. (#3782 — thanks @xenstar)session→arena-auth-prod-v1) — the lmarena credential hint asked for a cookie namedsession, but lmarena.ai's real auth cookie isarena-auth-prod-v1, so users who pasted onlysession=…hit validation failures. The credential name, placeholder and storage keys now use the correct name (the legacysessionkey is retained for back-compat with already-saved credentials). (#3810 — thanks @xspylol)maxeffort toxhighby default — OpenAI-compatible providers do not accept literalmax, but some upstreams (for example DeepSeek through OpenRouter) supportxhigh;maxnow maps toxhighunless the target model explicitly opts out ofxhigh, with Claude alias variants still honoring the canonical Claude opt-out list. (#3826 — thanks @rdself)…-low……-max) 404'd upstream and tripped the circuit breaker into a misleading "rate-limited" state; the suffix is now stripped before dispatch. (#3807 — thanks @zhiru)/v1/models); transient failures now surface an error state but stay visible. (#3849 — thanks @lukmanc405)OMNIROUTE_OPENCODE_GO_QUOTA_URLoverride hint. (#3838 — thanks @adivekar-utexas)claude-sonnet-4.6) had no pricing row and reported $0.00; the rows were added. (#3835 — thanks @artickc)embeddedServiceskeys across 37 locales — theembeddedServicesstrings showed__MISSING__in 37 locales; they are now translated. (#3819 — thanks @rafacpti23)🔒 Security & Hardening
🧹 Internal / Quality / Docs
SUPPLY_CHAIN.md— the new security doc lacked thetitle:frontmatter that MDX pages require, which broke the production Build + Docker Hub publish; the frontmatter was added. (#3864)aquasecurity/trivy-action0.28.0 → 0.36.0 (#3862)chat.tsgrowth — the per-file size baseline was re-frozen to absorb the formatting/line-count growth from this cycle's chat-core and combo fixes (manual edits, never an automatic upward ratchet). (#3823, #3833 — thanks @diegosouzapw)[id]provider-detail strangler-fig decomposition [refactor] Decompose providers/[id]/page.tsx god-component (12,882 LOC → ≤800, phased/strangler) #3501, Vertex Express-mode keys, Antigravity discovery using a current user-callable model id) and the same-provider 503 fall-through resilience test; de-flaked the compression benchmark reproducibility test (sequential passes) and the ServiceSupervisor crash test (poll instead of fixed sleep). No production code changed. Also documentedOMNIROUTE_MAX_PENDING_MIGRATIONS([BUG] v3.8.15 — Server exits immediately under systemd (Linux, production) #3416) in.env.example+ENVIRONMENT.md. (thanks @diegosouzapw)🙌 Contributors
Huge thanks to everyone whose work shipped in v3.8.26: