mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-02 21:32:10 +03:00
8eded5ebf2d54a266978ca967950fa56ececbbd8
1257 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f628135e3c |
fix(security): scope OAuth callback postMessage to a trusted-origin allowlist (port from 9router#998) (#4372)
The OAuth callback at `/callback` previously fell back to
`window.opener.postMessage({ code, state, ... }, "*")` whenever the opener
was cross-origin. The fallback was intended to support remote-OmniRoute +
local-loopback callbacks (where opener and callback live on different
origins), but the same code path also delivers the OAuth code/state to any
hostile opener that pops the well-known callback URL — letting that
attacker complete the OAuth flow as the user.
Replace the wildcard fallback with iteration over a fixed allowlist:
`window.location.origin` (same-origin parent — the popup-mode dashboard)
plus Codex's fixed loopback helper (`http://localhost:1455` and the IPv4
literal `http://127.0.0.1:1455`). The browser drops `postMessage` to any
opener whose actual origin is not in `targetOrigin`, so the message reaches
only known parents and is silently dropped for any other. The same-origin
fallback path is unchanged — methods 2 (`BroadcastChannel`) and 3
(`localStorage` storage event) still cover same-origin openers that COOP
severed.
The `openerSameOrigin` probe stays in place to drive the auto-close vs
manual-copy UI decision (no behavior change for the success path).
Adds a regression test (`tests/unit/ui/oauth-callback-postmessage-scope.test.tsx`)
that mounts the page with a stubbed cross-origin opener and asserts no
`postMessage` call ever uses `"*"` and every call lands on an allowlisted
origin. The test failed against the pre-fix code (red), passes after the
fix (green) — TDD per CLAUDE.md hard rule #18.
Partial port of upstream decolua/9router#998: the upstream PR also
re-enabled TLS verification on a DNS-bypass fetch in `open-sse/utils/proxyFetch.js`;
that part is N/A here because OmniRoute's `proxyFetch.ts` never disabled
TLS verification (no `rejectUnauthorized: false` anywhere in the file).
Inspired-by: https://github.com/decolua/9router/pull/998
Co-authored-by: aeonframework <aeon@aeonframework.dev>
|
||
|
|
7ef11eb94e |
fix(api): persist max_input_tokens/max_output_tokens when adding a custom model (#4349)
The POST /api/provider-models handler read the rest of the body but never the two token-limit fields, and addCustomModel() had no parameter for them, so the form values were dropped on write while the DB layer and /v1/models catalog already round-trip inputTokenLimit/outputTokenLimit. Accept the two optional limits in the schema, forward them through the handler, and persist them in addCustomModel(). TDD: failing-then-passing unit test. Reported-by: codename-zen (https://github.com/decolua/9router/issues/1294) Co-authored-by: codename-zen <263238141+codename-zen@users.noreply.github.com> |
||
|
|
2dc38c1618 |
fix(db): cascade-delete orphaned model aliases when a provider is removed (#4348)
* fix(db): cascade-delete orphaned model aliases when a provider is removed (port from 9router#1409) Deleting a custom provider removed its connections and node but left the imported model-alias rows (key=<alias>, value="<providerId>/<model>") behind, so re-importing the same provider was blocked by stale "already exists" aliases. Add a deleteModelAliasesForProvider(providerId) DB helper that drops every alias whose stored value begins with "<providerId>/", and call it from the provider-node DELETE handler so a fresh import is unblocked. Reported-by: nguyenvanhuy0612 (https://github.com/decolua/9router/issues/1409) Co-authored-by: nguyenvanhuy0612 <57367674+nguyenvanhuy0612@users.noreply.github.com> * chore(quality): rebaseline models.ts file-size to 1221 (#1409 + sibling #1294 growth) --------- Co-authored-by: nguyenvanhuy0612 <57367674+nguyenvanhuy0612@users.noreply.github.com> |
||
|
|
94f474b943 |
fix(providers): label a deactivated account distinctly from a revoked token (#4353)
A Codex connection whose OAuth refresh is fully healthy but whose ChatGPT
account has been deactivated by the provider gets a 401 from the upstream
API. The connection test labeled that the same as a bad credential
("Token invalid or revoked" -> upstream_auth_error), so an operator could not
tell a deactivated account from a revoked token. The test now reads the
401/403 body and, when it indicates account deactivation, classifies it as
account_deactivated (which the dashboard already renders as "Account
Deactivated"); a plain auth 401 is unchanged.
Reported-by: ntdung6868 (https://github.com/decolua/9router/issues/1444)
Co-authored-by: ntdung6868 <103993527+ntdung6868@users.noreply.github.com>
|
||
|
|
9112056a2b |
fix(providers): bound the OAuth connection-test probe with a timeout (#4347)
* fix(providers): bound OAuth connection-test probe with a timeout (port from 9router#1449) The OAuth path of "Test Connection One-by-One" called bare fetch() with no AbortController/signal, so a provider probe that accepted the socket but never responded wedged the test queue forever. Both the initial probe and the post-refresh retry are now bounded with AbortSignal.timeout(30s) — matching the API-key path's existing budget — and a timed-out probe resolves as a failure with a clear "Test timed out after 30s" message in the route's normal error shape. Reported-by: ntdung6868 (https://github.com/decolua/9router/issues/1449) Co-authored-by: ntdung6868 <103993527+ntdung6868@users.noreply.github.com> * chore(quality): rebaseline providers test route file-size to 887 (#1449 + sibling #1444 growth) --------- Co-authored-by: ntdung6868 <103993527+ntdung6868@users.noreply.github.com> |
||
|
|
31f91cd23f |
fix(dashboard): show a disabled connection's last error in the row (#4352)
* fix(dashboard): show a disabled connection's last error in the row (port from 9router#1447) The provider card's error badge counts a disabled connection (isActive === false) that has an error — its effective status is still error/expired/unavailable — but the connection row hid the lastError text for disabled rows, so the operator saw the count without the cause. The row's error-visibility decision is extracted into shouldShowConnectionLastError() and now shows the error whenever there is one, regardless of the active toggle. Reported-by: ntdung6868 (https://github.com/decolua/9router/issues/1447) Co-authored-by: ntdung6868 <103993527+ntdung6868@users.noreply.github.com> * chore(quality): rebaseline ConnectionRow.tsx file-size to 942 (#1447 +1 import) --------- Co-authored-by: ntdung6868 <103993527+ntdung6868@users.noreply.github.com> |
||
|
|
d6ce094a60 |
fix(api): migrate deprecated Codex [features].codex_hooks to [features].hooks (#4342)
Codex renamed the `codex_hooks` feature flag to `hooks`; recent Codex CLI versions ignore the old key and warn. When OmniRoute rewrites an existing config.toml (configure/reset Codex provider) it now renames [features].codex_hooks -> [features].hooks, preserving the value and never clobbering an already-present `hooks`, then drops the deprecated key. The migration is a no-op when the flag is absent and runs on both the POST and DELETE config paths. Reported-by: Bian-Sh (https://github.com/decolua/9router/issues/1327) Co-authored-by: Bian-Sh <24520547+Bian-Sh@users.noreply.github.com> |
||
|
|
db362b0126 |
Release v3.8.30 (#4267)
Release v3.8.30 — see CHANGELOG.md [3.8.30] for the full release notes. |
||
|
|
3c9883bb73 |
Release v3.8.29 (#4126)
OmniRoute v3.8.29 — 115 commits since v3.8.28. Full CHANGELOG + 41 i18n mirrors. All content quality gates green (build, unit 8/8, vitest 188/188, PR test policy, quality gates extended, docs sync, quality ratchet). Remaining red CI checks are pre-existing release flakes (coverage-shard/integration/node-compat teardown), a new transitive undici advisory in electron devDeps, and a workflow-level CodeQL fail (0 open alerts). VPS-validated by the operator. |
||
|
|
f165efcd0b |
Release v3.8.28 (#4053)
* chore(release): open v3.8.28 development cycle * fix(ws): warm SSE auth import on LiveWS startup; relocate boot test to integration (#4063) The live dashboard WebSocket sidecar lazily import()-ed the SSE auth module inside the connection handler, only on the API-key path. That cold import pulls in hundreds of transitive modules and takes ~7s under tsx, blocking the single-threaded event loop. The first API-key WebSocket connection therefore stalled the loop long enough that any connection arriving in that window — e.g. a same-origin cookie client — could not complete its handshake and timed out. This was deterministic, not an "env flake": the boot test fires an API-key connection immediately followed by a cookie connection, so the cookie connection always raced the cold import and timed out (reproduced 3/3 locally and red on every CI run; proven via instrumented probes — reversing the order or warming the module first makes both connections open in ~20ms). Fix: - Memoize the auth-module import and warm it once at startup (before listen), so connection handling never pays the cold-import cost. Real improvement: the first API-key client no longer stalls the event loop for concurrent clients. - Relocate the boot test from tests/unit/cli to tests/integration. It spawns a real subprocess + WS server + SQLite (~9-11s); under the unit suite's --test-concurrency=20 it contended for CPU and destabilized the shard. The serial integration runner is its correct home; it still guards #4004's cookie-parse fix on every PR via the integration CI job. - Bump the test's startup/overall timeouts to absorb the eager auth warm. Makes `npm run test:unit` deterministically green (the only remaining unit red). Validated: relocated test 3/3 green via the integration runner (was 3/3 red); typecheck:core + eslint clean; confirmed it no longer matches the test:unit glob and does match tests/integration/*.test.ts. * fix(ws): start LiveWS sidecar with cwd at package root (#4055) (#4064) * chore(deps): bump ossf/scorecard-action from 2.4.0 to 2.4.3 (#4045) Integrado em release/v3.8.28. Patch de SHA do ossf/scorecard-action (2.4.0→2.4.3), mantém SHA-pin. Reds de CI são exclusivamente os shards flaky pré-existentes branch-wide (Unit 7/8, Integration, Coverage 7/8, Node 1/2) — não relacionados ao bump (PR deps-only). * deps: bump electron from 42.4.0 to 42.4.1 in /electron (#4049) Integrado em release/v3.8.28. Patch do electron (42.4.0→42.4.1). Reds de CI: shards flaky pré-existentes + PR Test Policy = falso-positivo (mudança deps-only sob electron/ não comporta teste de código) + Node 26(2/2) sem step (flake/infra). Precedente #3913/#3914 (electron dependabot mergeado nessas condições). * fix(auto): resolve built-in auto catalog combos (#4058) Integrado em release/v3.8.28. Resolve os IDs de catálogo `auto/*` built-in (combos virtuais) — corrige o 400 "No auto combos configured" em auto/best-coding etc. Ajuste de review: os mapas AUTO_TEMPLATE_VARIANTS/VALID_AUTO_VARIANTS duplicados em chat.ts e chatHelpers.ts foram extraídos para open-sse/services/autoCombo/builtinCatalog.ts (DRY), devolvendo chatHelpers.ts <800 LOC; baseline de chat.ts rebaselinado 1432→1458 (lógica nova). Fast QG + semgrep + dast verdes; 22/22 testes. * chore(docs): update Discord invite link to a non-expiring one (#4067) * chore(deps): freeze @huggingface/transformers in dependabot (hard-pin) (#4066) Integrado em release/v3.8.28. Congela @huggingface/transformers no dependabot (pin exato 3.5.2, load-bearing p/ LLMLingua + memory embeddings, VPS-validado #4014). Fast QG + semgrep + dast verdes. * ci(quality): flip TIA impacted-unit-tests gate from advisory to blocking (#4069) The pre-existing release unit test-debt that kept the TIA "Impacted unit tests" step advisory has been cleared: - #4030 restored 16 lossless Zod/registry reds (from the oyi77 modularize refactors). - #4063 fixed the last red — the LiveWS boot test — which was a real deterministic event-loop stall in the WS sidecar (cold ~7s lazy auth import racing a second connection), not an env flake; fixed (warm the import at startup) and relocated to the integration suite. A full workflow_dispatch ci.yml run on release/v3.8.28 then showed all 8 Unit Tests shards green. The remaining Integration Tests / Quality Ratchet reds are pre-existing and unrelated (combo/resilience env-flakes; eslint/i18n baseline drift). Removing continue-on-error makes PR->release block on unit-test regressions in the TIA-selected impacted set (fail-safe still runs the full unit suite on hub/unmapped changes). typecheck:core was already blocking. Closes the fast-gates "no tests on PR->release" hole (Quality Gate v2 / Fase 9, P2). * docs(compression): document LLMLingua optional deps + on-demand install (#4061) Integrado em release/v3.8.28. Docs LLMLingua optional deps + on-demand install (F3.1). * feat(dashboard): Combo Studio connection-cooldown badge (U1b Slice 2) (#4068) Integrado em release/v3.8.28. Combo Studio connection-cooldown badge (U1b Slice 2 / F5.1). * feat(compression): record Context Editing telemetry (engine: context-editing) (#4062) Integrado em release/v3.8.28. Context Editing telemetry (F4.1). * feat(sse): Context Editing relay coverage + 400-fallback (#4065) Integrado em release/v3.8.28. Context Editing relay coverage (cc-*) + 400-fallback (F4.2/F4.3). Conflito de file-size-baseline.json (vs #4062) resolvido por união (ambas justificativas + base.ts 1292 + chatCore.ts 5898). Validado local no tree mergeado: typecheck:core ✓, eslint ✓, check:file-size ✓, 4/4 testes ✓; semgrep + semgrep-cloud verdes. Fast QG enfileirado (saturação de runner) — mergeado nos gates de política verificados (precedente #4034/#4020). * feat(providers): add OrcaRouter (OpenAI-compatible routing gateway) (#4070) Integrado em release/v3.8.28. Adiciona o provider OrcaRouter (OpenAI-compatible, API-key, DefaultExecutor). Ajuste de review: rebaseline de file-size de providers.ts 3147→3159 (+12 da entrada OrcaRouter). Validado local no tree sincronizado: provider-consistency ✓, docs-counts STRICT 227 ✓, typecheck:core ✓, teste 3/3 ✓, eslint ✓; semgrep + semgrep-cloud verdes. Fast QG/dast enfileirados (saturação de runner) — merge nos gates de política verificados (precedente #4034/#4065). * test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 (#4078) * test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 Every test process resolved DATA_DIR to the same default (~/.omniroute) when the env var was unset (src/lib/dataPaths.ts::resolveDataDir), so concurrent test files opened the SAME on-disk storage.sqlite. node:test spawns a process per file and Stryker spawns one per sandbox, so this shared file caused cross-file state races: - SQLite lock contention that hung `npm run test:unit` under high --test-concurrency (the ~95-min local hang), and - the non-deterministic baseline that forced stryker.conf.json to concurrency: 1, which in turn could not finish the ~15k-mutant run inside the nightly timeout (the cancelled 2026-06-16/17 nightly-mutation runs) — blocking Quality Gate v2 / Fase 9 Onda 2. open-sse/utils/setupPolyfill.ts could NOT host the fix: it is imported by production (bin/omniroute.mjs, proxyFetch.ts, proxyDispatcher.ts), where redirecting DATA_DIR would point the live SQLite DB at a throwaway temp dir. So this adds a TEST-ONLY tests/_setup/isolateDataDir.ts that gives each process its own temp DATA_DIR when none is set (tests that set DATA_DIR explicitly still win), wired via --import into the test, mutation and CI invocations. Verified: - Stryker dry-run A/B at concurrency=4: FAILS without the isolation import (account-fallback-service tap exit 9, a cross-file race) and PASSES with it. - Full `npm run test:unit` green with isolation (0 fail; a one-off chatcore-translation-paths timeout flake did not reproduce and passes 3/3 isolated) and noticeably faster — the DB lock contention is gone. - New tests/unit/isolate-datadir.test.ts guards the contract (unique temp DATA_DIR when unset; explicit DATA_DIR respected). Wired the --import into: package.json (13 test scripts), stryker.conf.json (tap.nodeArgs + concurrency 1→4), .github/workflows/quality.yml (TIA step), ci.yml (the 5 unit/coverage/integration commands), and bumped nightly-mutation.yml timeout 120→180 for the first cold run before the incremental cache is seeded. * ci(quality): run the TIA gate at CI concurrency (4) to stop oversubscription flakes The TIA "Impacted unit tests" step (made blocking in #4069) ran its fail-safe via `npm run test:unit` — concurrency=20, tuned for multi-core dev machines. On a 4-vCPU CI runner that is 5x oversubscribed, so timing-sensitive tests flake under the load (e.g. `db-backup-extended` "The database connection is not open", `chatcore-translation-paths` upstream-timeout). That intermittently fails a blocking gate on legitimate PRs — exactly what surfaced on the DATA_DIR-isolation PR, whose package.json/workflow changes trip the __RUN_ALL__ fail-safe. Run both the impacted set and the fail-safe at --test-concurrency=4, matching the stable ci.yml unit job. Adds a `test:unit:ci` script (test:unit at concurrency=4). The DATA_DIR isolation in this PR keeps the parallel run race-free, so the only change here is matching the runner's core count. Verified locally: db-backup-extended passes 8/8 in isolation (5 with isolation, 3 without). * docs(quality-gates): reconcile gate inventory with ci.yml + add ROI rationalization backlog (#4095) The "authoritative" gate inventory in QUALITY_GATES.md had drifted from ci.yml: it omitted 9 wired gates — `audit:deps`, `check:tracked-artifacts`, `check:lockfile`, `check:licenses` (lint job), `check:dead-code`, `check:cognitive-complexity`, `check:type-coverage`, `check:codeql-ratchet` (quality-gate job), and `check:pr-evidence` (pr-test-policy job). You can't rationalize an inventory you can't trust, so this reconciles it first. Adds those 9 rows to their job tables and a "Rationalization Backlog (ROI review)" section capturing the Fase 9 Onda 3 findings: mechanical merge/dedup candidates (CVE scanners audit:deps↔osv, the two complexity ESLint passes, cycles↔circular-deps, the two /api anti-hallucination gates, the doubly-run check:docs-sync, check:node-runtime ×11) and the operator-only flip/drop decisions (typecheck:noimplicit vs the type-coverage ratchet, test:vitest:ui parked fails, check:secrets frozen FPs, openapi-security-tiers, pr-evidence, the orphaned semgrep baseline). Also flags the undocumented advisory docs-lint job and the standalone scanner workflows. Docs-only — no gate behavior changes. The merges (CI changes) and flips (policy) are deferred to operator-scoped follow-ups; this PR only makes the map accurate. * test(dashboard): smoke e2e for the Combo Live Studio page (#4075) Integrated into release/v3.8.28 * fix(sse): friendly 413 message for ChatGPT web payload-too-large (#4080) Integrated into release/v3.8.28 * feat(sse): port Claude Code quota-probe bypass + command meta-request helpers (#4083) Integrated into release/v3.8.28 * feat(api): exact offline token counting for count_tokens fallback via tiktoken (#4087) Integrated into release/v3.8.28 * feat(compression): RTK learn/discover (sample source + API + UI) (#4088) Integrated into release/v3.8.28 * feat(dashboard): 2026-06-17 free-tier refresh — honest catalog, uncapped + boost tiers, Layout A budget table (#4089) Integrated into release/v3.8.28 * feat(mitm): capture-pipeline self-test route (Gap 12) (#4093) Integrated into release/v3.8.28 * fix(mitm): crash-safe system-state teardown + socket timeouts (ProxyBridge-inspired hardening) (#4084) Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green) * feat(mitm): attribute intercepted requests to originating process (Gap 1) (#4085) Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green) * fix(sse): route image requests only to confirmed-vision combo targets (#4071) Integrated into release/v3.8.28 * fix(security): injection guard respects INJECTION_GUARD_MODE DB feature flag (#4077) Integrated into release/v3.8.28 * fix(ws): proxy LAN /live-ws upgrades and add unset JWT_SECRET warning (#4079) Integrated into release/v3.8.28 * fix(dev): force webpack in custom dev server (Turbopack 16.2.x panics) (#4092) Integrated into release/v3.8.28 * ci(quality): dedup the doubly-run check:docs-sync + record validated ROI backlog (#4099) Onda 3 (gate ROI-review) Phase 2. Two parts, both low-risk: 1. Remove the standalone `check:docs-sync` from the `lint` job — it already runs in the `docs-sync-strict` job (via `check:docs-all`) and the husky pre-commit hook, so the `lint`-job copy was a pure duplicate. No coverage lost. 2. Update the Rationalization Backlog in QUALITY_GATES.md with trust-but-verify findings: several "obvious" merges/flips from the ROI review turned out to hide debt and are NOT clean drop-ins — - CVE merge (audit:deps→osv): different semantics (hard high/critical vs regression-ratchet) — keep both. - cycles→circular-deps: dpdm reports 91 cycles (can't promote to blocking) and is broader-scope than the green curated check:cycles — keep both. - openapi-security-tiers flip: blocked by traffic-inspector routes missing the x-loopback-only annotation. - complexity + /api merges: valid but real config/script surgery — deferred. - node-runtime ×11: ~10s savings vs a cheap guard — low ROI, skip. The remaining flips (typecheck:noimplicit, test:vitest:ui, check:secrets, pr-evidence, semgrep) are operator policy decisions, left for the owner. * chore(deps): bump actions/github-script from 7 to 9 (#4046) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/setup-node from 4 to 6 (#4048) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/upload-artifact from 4 to 7 (#4044) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/cache from 4.3.0 to 5.0.5 (#4047) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * deps: bump the development group with 10 updates (#4051) Integrated into release/v3.8.28 (dependabot dev group; cyclonedx 4->5 verified compatible with the SBOM invocation --ignore-npm-errors/--output-format JSON/--output-file) * fix(dashboard): event-driven fail-open auto-refresh for embedded log views (#4054) (#4103) The Request Logger gated each auto-refresh tick on a static document.visibilityState === "visible" read. Hosts that report a permanent non-"visible" state without ever firing a visibilitychange event (Docker dashboard wrappers, embedded/proxied webviews) froze auto-refresh entirely — only the manual Refresh button worked, a regression from 3.8.24's unconditional polling. The pause is now event-driven and fail-open: visibleRef starts true and is only flipped to false on a real visibilitychange → hidden transition, so a host that never signals a genuine background transition keeps polling, while normal browser tabs still pause when actually backgrounded. Regression test reproduces the misreporting-host case (RED) and the perf guard is re-encoded under the event-driven semantics. * fix(docker): raise build-stage Node heap to stop production-build OOM (#4076) (#4104) The Docker builder stage ran `npm run build` with V8's default heap ceiling (~2 GB). After #4052 forced the heavier webpack engine (Turbopack panics on this Next.js version), the production optimization pass exceeded that ceiling and the build died with "FATAL ERROR: ... JavaScript heap out of memory" at [builder] npm run build. The builder stage now sets NODE_OPTIONS=--max-old-space-size (default 4096 MB, overridable via --build-arg OMNIROUTE_BUILD_MEMORY_MB) before the build; the value propagates to the spawned next build (resolveNextBuildEnv spreads process.env). Build-only — the runtime heap on the runner stage is unchanged, and CI/local builds (which invoke npm run build directly) are unaffected. Regression guard: tests/unit/dockerfile-build-heap-4076.test.ts asserts the builder stage sets the heap ceiling, before npm run build, at >= 4096 MB. * feat(agent-bridge): portable JSON import/export of config (Gap 4) (#4094) Integrated into release/v3.8.28 * feat(cli): add 'omniroute launch' zero-config Claude Code launcher (#4097) Integrated into release/v3.8.28 (Fast QG TIA red = pre-existing env-doc-contract drift [MITM_IDLE_TIMEOUT_MS/TURBOPACK from #4084/#4092] + opencode-plugin-dist env flake; #4097 own test 3/3 green) * feat(mitm): loop-guard self-check + verbosity control in server.cjs (Gaps 14+15) (#4101) Integrated into release/v3.8.28 (rebased onto release — dropped the already-squash-merged #4084 commits; only the Gaps 14+15 loop-guard/verbosity delta remains) * feat(sse): generic 400 field-downgrade retry + Groq field stripping (#4096) Integrated into release/v3.8.28 * feat(providers): add Wafer AI (Anthropic-compatible, Bearer auth) (#4098) Integrated into release/v3.8.28 * chore(docs) * fix(responses): clear /v1/responses keepalive timer on cancel/abort (timer + CPU leak) (#4105) Integrated into release/v3.8.28 (r7). * perf(gemini): cache reasoning close-tag regex instead of recompiling per token (#4106) Integrated into release/v3.8.28 (r7). * fix(usage): reap orphaned pending-request details (unbounded memory leak) (#4107) Integrated into release/v3.8.28 (r7). * perf(stream): use structuredClone instead of JSON round-trip for per-chunk reasoning split (#4108) Integrated into release/v3.8.28 (r7). * fix(dashboard): restore Update Available banner with npm-binary-free version fallback (#4100) (#4112) getLatestNpmVersion() derived the latest version only from the npm CLI binary and returned null on any error, so Docker/desktop/locked-down installs without npm on PATH silently hid the home banner even when an update existed. Add resolveLatestVersion() (npm CLI -> registry HTTP fallback -> logged warning) and harden version parsing for v-prefix/pre-release strings. Extracted into testable src/lib/system/versionCheck.ts with TDD coverage. * fix(auth): prune expired entries from login brute-force guard map (unbounded growth) (#4111) Integrated into release/v3.8.28 (r8) * fix(logger): hard-cap the error-dedup map to bound memory under unique-message bursts (#4113) Integrated into release/v3.8.28 (r8) * fix(circuit-breaker): enforce MAX_REGISTRY_SIZE (declared but never applied) (#4114) Integrated into release/v3.8.28 (r8) * perf(obfuscation): cache per-word regexes instead of recompiling every request (#4109) Integrated into release/v3.8.28 (r8) * perf(registry): precompute model->provider index in parseModelFromRegistry (#4110) Integrated into release/v3.8.28 (r8) * fix(timers): unref background interval timers so they don't block clean shutdown (#4117) Integrated into release/v3.8.28 (r8) * fix(webhook): clear abort timer in finally to avoid dangling timers on fetch error (#4115) Integrated into release/v3.8.28 (r8) * fix(combo): detach per-target listener from shared hedge abort signal (#4116) Integrated into release/v3.8.28 (r8) * chore(release): finalize v3.8.28 CHANGELOG + reconcile env-doc contract - Build the complete [3.8.28] CHANGELOG section (55 bullets) covering every commit since v3.8.27, grouped by type with PR back-references and human contributor attribution (artickc's memory-leak/perf cluster, OrcaRouter, Wafer AI, MITM gaps, etc.); move the OrcaRouter bullet out of [Unreleased]. - Inject the EN [3.8.28] section into all 41 i18n CHANGELOG mirrors (parity). - Reconcile the env/docs contract: document MITM_IDLE_TIMEOUT_MS + MITM_VERBOSE in .env.example and ENVIRONMENT.md; allowlist the framework-internal TURBOPACK and the Claude Code ANTHROPIC_AUTH_TOKEN in check-env-doc-sync. - Fix 3 broken relative links in docs/providers/AGENTROUTER.md (regressed when the file was relocated this cycle) so docs-sync-strict passes. * fix(quality): treat test→test renames as relocations, not deletions The anti-test-masking gate's subcheck-1 collected deleted AND renamed test files via `--diff-filter=DR --name-only` and flagged every one as "deleted — human review required", contradicting its own documented contract ("DELETADOS ou renomeados-e-NÃO-substituídos"): a rename test→test IS a substitution (the test moved, coverage preserved). This false-positived on #4063's legitimate relocation of live-ws-startup.test.ts (unit/cli → integration, asserts 2→2) and would block every PR that relocates a test — surfacing only at release-day because the Fast QG (PR→release) doesn't run test-masking. The gate now parses `--name-status -M`: true deletions and test→non-test renames still flag; a test→test rename is run through the assert-reduction check across the move, so a clean relocation passes while gutting-via-rename (dropped asserts / new tautologies / skips) still fires. Adds partitionDeletedRenamed + 6 regression tests. --------- Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: jinhaosong-source <jinhao.song@myflashcloud.com> Co-authored-by: diego-anselmo <contato@diegoanselmo.com.br> Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com> Co-authored-by: Rahul sharma <sharmaR0810@gmail.com> Co-authored-by: Chirag Singhal <76880977+chirag127@users.noreply.github.com> Co-authored-by: NOXX - Commiter <artur1992123@mail.ru> |
||
|
|
fa367dd99e |
Release v3.8.27 (#3968)
* chore(release): open v3.8.27 development cycle * fix(security): polynomial ReDoS in comboAgentMiddleware regex (#3982) * fix(security): eliminate polynomial ReDoS in comboAgentMiddleware <omniModel> regex (CodeQL js/polynomial-redos) CACHE_TAG_PATTERN wrapped the tag in an unbounded `(?:\\n|\n|\r)*` prefix/suffix. On an unanchored `.test()`/`.exec()` that is O(n²) on inputs with many newlines (CodeQL js/polynomial-redos, alerts #612/#613). The surrounding runs are irrelevant to detecting/capturing the tag, so the detection pattern now matches only the core `<omniModel>([^<]+)</omniModel>`; the global strip pattern still consumes the wrapping newlines (combo.ts streaming, #531) but BOUNDED ({0,16}) so it stays linear. Behavior preserved: detection, model extraction, multi-tag stripping (#454) and blank-line cleanup all unchanged (107 related tests green). Adds ReDoS-safety regression tests (50k-newline inputs complete in <1ms). * docs(changelog): add #3982 ReDoS fix to [3.8.27] * ci(security): harden workflows — artipacked persist-credentials + cache-poisoning + SC2086 (#3965) * Refine provider quota card display (#3969) Integrated into release/v3.8.27 * feat: add sidebar group separator toggles (#3971) Integrated into release/v3.8.27 * Gate control-plane proxy direct fallback (#3963) Integrated into release/v3.8.27 * Capture actual upstream provider requests (#3941) Integrated into release/v3.8.27 * ci(quality): flip require-tighten + osv + Trivy to blocking (v3.8.27 cycle-end) (#3984) * fix(resilience): respect connection cooldown stored as numeric epoch (#3954) (#3995) rate_limited_until is a TEXT column, but setConnectionRateLimitUntil (Antigravity full-quota path) persists a raw epoch number that SQLite coerces to a numeric string ("1781696905131.0"). The selection predicate isAccountUnavailable then did new Date("1781696905131.0") -> NaN, so the cooling connection was never skipped and the router kept dispatching to rate-limited accounts. Normalize numeric-epoch strings (and number/Date/ISO) via a shared cooldownUntilMs() helper in isAccountUnavailable / getEarliestRateLimitedUntil / filterAvailableAccounts / parseFutureDateMs. ISO behavior preserved. * fix(providers): fetch live /models for LLM7 and BytePlus (#3976) (#3996) llm7 and byteplus carry a real modelsUrl but were not classified by any live-fetch branch of the model-import route, so their hardcoded 4-entry registry catalog was served (source local_catalog) instead of the upstream catalog. Add both to NAMED_OPENAI_STYLE_PROVIDERS so the route probes <baseUrl>/models and serves the live list, falling back to the local catalog only on fetch failure. * fix(dashboard): logs auto-refresh reads live visibility, not a stale mount ref (#3972) (#3997) The auto-refresh interval gated each tick on visibleRef, seeded once at mount and updated only by a visibilitychange event. A tab mounted while document.visibilityState is 'hidden' (background load, bfcache, embedded/proxied webviews) with no later visibilitychange left the ref false forever, so the interval ticked but never fetched — only the manual button worked. Read the live document.visibilityState in the tick instead. * feat(compression): add Indonesian caveman rules and language pack (#3975) Integrated into release/v3.8.27 (cherry picked from commit |
||
|
|
81a37b67ed |
Release v3.8.26 (#3875)
OmniRoute v3.8.26 — see CHANGELOG.md [3.8.26] for the full notes. Highlights: Vertex AI media generation (#3929), GLM-5.2 effort-tier routing (#3885), sticky round-robin combos (#3846), OpenRouter connection presets (#3878), compression prompt-cache fix (#3936/#3890), and a security pass (form-data/vite + workflow hardening, #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> |
||
|
|
35dbf0eea1 |
Release v3.8.25 (#3866)
* chore(release): continue v3.8.25 development cycle after main code-sync (r5) main fast-forwarded to release/v3.8.25 (#3863): unblocked Build+Docker via #3864, plus #3837 (mimocode proxy) and #3862 (trivy bump). This marker re-opens the umbrella PR for further v3.8.25 work. No version bump. * fix(db): persist the Keep-latest-backups retention setting (#3834) (#3867) * fix(oauth): clear GitLab Duo setup message instead of 500 (#3861) (#3868) * test(oauth): prove refresh_token preserved on real gemini-cli/antigravity dispatch (#3850) (#3869) * feat(compression-ui): unified compression config UI — per-engine pages + combos editor + menu + WS default-on (#3860) Integrated into release/v3.8.25 — feat(compression-ui): unified compression configuration UI (Compression Hub + per-engine Lite/Aggressive/Ultra pages + combos editor + sidebar entry + live-WS default-on). File-size re-baselined for sidebarVisibility.ts/chatCore.ts growth; orphan ws test relocated to a collected path. * docs(changelog): complete the v3.8.25 release notes + credit all contributors Audited every commit since v3.8.24 and filled the gaps the [3.8.25] section was missing: a New Features section (compression engines + Compression Studios #3848, compression UI #3860, injection-guard #3857, kiro discovery #3836, Veo #3839, mimocode proxy #3837, Arena ELO flag #3821), 9 more Fixed entries (#3811/#3807/#3759/#3849/#3838/#3835/#3814/#3820/#3819), a Security section (CCR IDOR #3859, supply-chain #3824), and an Internal/Quality section. Every contributor and issue reporter is now credited. * docs(changelog): restore + complete the v3.8.25 release notes Re-adds CHANGELOG.md (a prior server-side commit accidentally dropped it) with the complete, audited [3.8.25] section: New Features, the full Fixed list, Security & Hardening, and Internal/Quality — every contributor and issue reporter credited. * chore(release): finalize v3.8.25 — reconcile CHANGELOG + i18n mirrors, document OMNIROUTE_MAX_PENDING_MIGRATIONS, green the unit suite Release-gate reconciliation for v3.8.25: - CHANGELOG: dated 2026-06-14, linked #3826, rolled up file-size re-baselines (#3823/#3833), recorded the test-greening; re-synced all 41 i18n CHANGELOG mirrors. - Documented OMNIROUTE_MAX_PENDING_MIGRATIONS (#3416) in .env.example + ENVIRONMENT.md. - Greened the unit suite (was merged red on 4 CI shards): aligned 10 stale tests to this cycle's intended behavior (#3838/#3822/#3501/SOCKS5/Vertex-Express/Antigravity) and the same-provider 503 fall-through test; de-flaked the compression benchmark reproducibility and ServiceSupervisor crash tests. No production code changed. * ci(security): clear OpenSSF Scorecard code-scanning noise + harden workflow token permissions The Security tab held 155 open alerts, ALL from the advisory OpenSSF Scorecard tool (#3824) — supply-chain/posture scores, not code vulnerabilities — which drowned out real CodeQL findings. - scorecard.yml: stop uploading SARIF to the code-scanning tab (drop the upload-sarif step + the now-unused security-events: write). The run still produces the OpenSSF badge (publish_results) and a downloadable SARIF artifact. - TokenPermissions hardening (the high-severity, genuinely-valuable subset): set each workflow's top-level token to read-only and grant the exact writes at the job level that needs them — npm-publish (id-token/packages on publish jobs), docker-publish (packages on build), electron-release (contents on build/release, id-token/packages on publish-npm), build-fork (packages on build), claude (empty top-level; job grants its own). The 155 existing alerts were dismissed. Not adopting repo-wide SHA-pinning (143 PinnedDependencies advisories) — declined. * test(integration): align stale wiring/socks5 integration tests to this cycle's behavior These were red on the CI Integration job (pre-existing). No production code changed: - integration-wiring: the combos page no longer renders a per-page EmailPrivacyToggle (#3822 consolidated it into Settings → Appearance); the provider-detail test-result masking and upstream-proxy copy moved to decomposed components (#3501 BatchTestResultsModal / UpstreamProxyCard) — assertions now read the owning files. - api-routes-critical: SOCKS5 is now enabled by default (opt-out), so the disabled- rejection test must set ENABLE_SOCKS5_PROXY=false explicitly (an unset env now means enabled). (The ~32 live-Gemini integration tests are gated on OMNIROUTE_API_KEY and skip in CI; they only 'fail' locally when that key is present without a running server.) |
||
|
|
f42e8fa751 |
feat(mimocode): per-account proxy support for multi-account round-robin (#3837)
Integrated into release/v3.8.25 — feat(mimocode): per-account proxy for multi-account round-robin (runWithProxyContext per account, keyed by fingerprint). Orphan test relocated to a collected vitest path (14/14 green). |
||
|
|
d728bfbb1e |
Fase 8 · Bloco D — injection-guard em todas as rotas LLM + red-team (#3857)
Integrated into release/v3.8.25 — Fase 8 Bloco D (injection-guard em todas as rotas LLM + red-team). |
||
|
|
4ffc55cfe4 |
feat(compression): compression engines + async pipeline + Compression Studios (#3848)
Integrated into release/v3.8.25. |
||
|
|
7c080941d1 | feat(connections): per-connection disable-cooldown opt-out (#2997) (#3852) | ||
|
|
2670a0a819 |
docs(ui): clarify routing settings copy for strategy sync + sticky limit (#3843)
Clarifies that the Default Strategy control syncs both new combo defaults and global account fallback routing, and updates the Round Robin sticky-limit helper text to call out account-level fallback behavior. Copy-only change to ComboDefaultsTab + en.json. Integrated into release/v3.8.25. Co-authored-by: Abhishek Divekar <adivekar@utexas.edu> |
||
|
|
948cf1f92c |
feat(kiro): live per-account model discovery via ListAvailableModels (#3836)
Kiro's catalog is per-account / per-tier (and admin-curated for IAM Identity Center orgs), which the static registry can't reflect. The models route now discovers the live list from the CodeWhisperer ListAvailableModels API with the stored OAuth token (Builder ID / social and IdC accounts; profileArn only as a retry to avoid 403, region-matched with us-east-1 fallback), falling back to the static registry catalog when the token is missing/expired or the upstream is unavailable so import never breaks. Integrated into release/v3.8.25. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
058946bd04 |
fix(models): don't auto-hide transient (rate-limited/timeout) failures on Test All (#3849)
With Auto-hide failed models on (default), a Test All sweep across 10+ models in parallel reliably trips per-account rate limits on subscription-tier providers, and the 429'd/timed-out models were auto-hidden — silently removing working models from /v1/models with no easy recovery. evaluateTestAllEntry now surfaces transient failures (rateLimited/isTimeout) as an 'error' icon but keeps them visible; only genuine (non-transient) failures are still auto-hidden. Integrated into release/v3.8.25. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
f2f909bd7f |
fix(ui): expand request log table height with vertical resize (#3820)
The request log table is given a comfortable minimum height (~10 rows) and is user-resizable vertically, replacing the previous flex/overflow-hidden constraints that clipped it short. Pure layout change to the logs page and RequestLoggerV2 card. Integrated into release/v3.8.25. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
772e6ba493 |
Consolidate email privacy control into Settings (#3822)
Moves the account email visibility control into Settings › Appearance (above Show Sidebar Items) and removes the page-level email reveal buttons from combos, logs, provider detail, provider quota, quota sharing, and the edit-connection modal. The global masking state is unchanged — existing account labels still consume the shared emailPrivacyStore — so one toggle now governs masking everywhere. The old EmailPrivacyToggle component is replaced by AccountEmailVisibilitySetting. Integrated into release/v3.8.25. Co-authored-by: R.D. <rogerproself@gmail.com> |
||
|
|
5875c7993f | fix(providers): surface real Devin error + fix Windsurf auth instructions (#3324) (#3829) | ||
|
|
ef324cd00e |
fix(models): preserve eye-hidden models across auto-sync (#3782) (#3816)
* fix(models): preserve eye-hidden models across auto-sync (#3782) * chore(quality): re-baseline file-size for models.ts growth (#3782) |
||
|
|
24c785a3ba |
fix(v3.8.24): plugins menu + proxy IP-family selector + CodeQL/test cleanup (#3800)
Surfaces the Plugins page (marketplace, #3656) in the sidebar; adds the proxy IP-family selector (auto/ipv4/ipv6) completing #3777's UI; clears the remaining CodeQL URL-substring alerts; covers #3799 with tests and fixes the costs-section count. |
||
|
|
c8dee8c5f7 |
feat: free provider rankings page by Arena AI ELO scores (#3799)
Adds a dashboard page + /api/free-provider-rankings route ranking free providers by model ELO/intelligence scores. Pure computation over the existing provider registry + model-intelligence data (no external fetch). Sidebar entry included. |
||
|
|
76a07cf7a5 |
Release v3.8.24 (#3747)
Release v3.8.24 — see CHANGELOG.md [3.8.24] for the full notes and the PR description for the contributors hall. Integration of release/v3.8.24 into main. |
||
|
|
de60b4b171 |
Release v3.8.23
* chore(release): open v3.8.23 development cycle
* fix(anthropic): strip top_p when temperature is set to avoid 400 (#3691)
Integrated into release/v3.8.23
* fix(vertex): support Vertex AI Express-mode API keys (#3690)
Integrated into release/v3.8.23
* fix(stream): error on empty Claude SSE instead of synthetic success (#3689)
Integrated into release/v3.8.23
* fix(oauth): stop token-refresh invalidation loop + harden proxy resolution (#3692)
Integrated into release/v3.8.23
* docs: add FUNDING.yml and Support section to README (#3698)
Integrated into release/v3.8.23
* feat: gemini - handle known ratelimits (#3686)
Integrated into release/v3.8.23
* fix: stream combo fails over on empty content-filtered response (#3685) (#3702)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(antigravity): preserve gemini-3.1-pro high/low budget tiers (#3696) (#3703)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(auto-combo): add auto-updating model intelligence scoring (#3660)
Integrated into release/v3.8.23
* fix(gemini): context-mode fallback for signatureless tool calls (#3688) (#3704)
* chore(quality-gate): reconcile file-size baseline (27 files + providerLimits.ts) (#3705)
* feat(vertex): dynamic model discovery via Generative Language models API (#3712)
Integrated into release/v3.8.23. Vertex dynamic model discovery — surfaces image models (imagen-*, gemini-*-image), embeddings and audio from the live Generative Language catalog, with cached→static fallback and the shared parseGeminiModelsList helper. Validated: parser test 5/5, typecheck:core clean.
* fix(combo): gate reasoning token buffer (#3700)
Integrated into release/v3.8.23. Makes the #3588 reasoning token buffer safe and configurable: only inflates max_tokens when the model has a known, non-default output cap and the buffered value fits inside it; otherwise preserves/clamps the client limit. Adds the reasoningTokenBufferEnabled kill switch (default ON). Validated: combo-routing-engine 81/81, combo-config 25/25, combo-quality-validator-reasoning 12/12, phase1f 10/10, typecheck:core clean.
* refactor(#3501): god-component Phase 1g-1j — client 4062→3408 LOC (-654) (#3717)
Phase 1g-1j of #3501: client 4062→3408 LOC. Pure extraction (ProviderPlaygroundPanel, useCommandCodeAuth, useExternalLinkFlow+ExternalLinkModal, useAuthFileHandlers) + loadConnProxies ReferenceError fix + phase1f test path fix.
Co-authored-by: oyi77 <14921983+oyi77@users.noreply.github.com>
* refactor(#3501): god-component Phase 1k-1m — client 3408→2553 LOC (-855) (#3721)
Phase 1k-1m of #3501: client 3408→2553 LOC. Pure extraction (useModelImportHandlers+ImportProgressModal, useModelVisibilityHandlers, ProviderModelsSection).
Co-authored-by: oyi77 <14921983+oyi77@users.noreply.github.com>
* docs(changelog): restore #3590 bullet lost on the v3.8.20 release branch
The fix itself reached main pre-tag via cherry-pick #3591, but its changelog
bullet (commit
|
||
|
|
9350a5d6c6 |
Release v3.8.22 (#3623)
* chore(release): open v3.8.22 development cycle * refactor(dashboard): extract ProviderDetailPageClient — #3501 Phase 0 (#3633) #3501 Phase 0: extract ProviderDetailPageClient + smoke test. Co-authored-by: oyi77 <oyi77@users.noreply.github.com> * refactor(dashboard): extract auth-import modals — #3501 Phase 1a (#3634) #3501 Phase 1a: extract 3 auth-import modal clusters. Co-authored-by: oyi77 <oyi77@users.noreply.github.com> * fix(db): reclassify localDb unexported modules as intentionally-internal (#3499) (#3635) Closes #3499 — reclassify localDb unexported modules as intentionally-internal (audit + honest gate framing). * refactor(db): move call_logs aggregations into callLogStats db module (#3500) (#3636) #3500 slice 1: call_logs aggregations → src/lib/db/callLogStats.ts (Rule #5). Byte-identical queries; TDD 6/6. * refactor(dashboard): extract EditCompatibleNodeModal — #3501 Phase 1b (#3638) #3501 Phase 1b: extract EditCompatibleNodeModal (cycle-safe via leaf constants module). Co-authored-by: oyi77 <oyi77@users.noreply.github.com> * refactor(db): move community_servers SQL into gamification db module (#3500 slice 3) (#3639) #3500 slice 3: community_servers SQL → gamification db module. * refactor(db): move usage_history SQL into usageAnalytics module (#3500 slice 2) (#3644) #3500 slice 2: usage_history/daily_usage_summary SQL → usageAnalytics db module. * refactor(db): move skills UPDATE + db-backups SQL into db modules (#3500 slice 5) (#3647) #3500 slice 5: skills UPDATE (allowlist) + db-backups SQL → db modules. * refactor(db): move usage_logs/semantic_cache/proxy_logs SQL into db modules (#3500 slice 4) (#3648) #3500 slice 4: usage_logs/semantic_cache/proxy_logs SQL → db modules. All internal routes done (2 external by-design remain). * chore(db-gate): reclassify external-DB reads, fully close #3500 (#3649) Closes #3500: reclassify external-DB reads; all internal raw-SQL migrated to db/ modules. * refactor(dashboard): extract pure helpers to providerPageHelpers — #3501 Phase 2 (#3653) #3501 Phase 2: extract pure helpers to providerPageHelpers (leaf, cycle-safe). Co-authored-by: oyi77 <oyi77@users.noreply.github.com> * refactor(dashboard): extract remaining shared helpers to providerPageHelpers — #3501 Phase 2b (#3658) #3501 Phase 2b: extract remaining shared helpers to providerPageHelpers (leaf, cycle-safe). Heavy modals unblocked. Co-authored-by: oyi77 <oyi77@users.noreply.github.com> * fix(reasoning): replay reasoning_content on plain DeepSeek turns (#1682) (#3632) Integrated into release/v3.8.22 * fix(kiro): route enterprise IAM Identity Center accounts to their regional endpoint (#3631) Integrated into release/v3.8.22 * refactor: small code cleanup (#3523) Integrated into release/v3.8.22 * fix(combo): skip same-provider targets on 408/500/502/503/504/524 errors (#3637) Integrated into release/v3.8.22 — circuit-breaker guard added in review (#1731v2) * feat(providers): add MiMoCode free-tier provider with bootstrap JWT auth (#3659) Integrated into release/v3.8.22 — page.tsx conflict resolved + NoAuthAccountCard re-applied to ProviderDetailPageClient in review. MiMoCode endpoint validated live. * Log Responses WebSocket calls in history (#3616) Integrated into release/v3.8.22 — Codex Responses WebSocket call history logging. * Add Claude Code routing preference for unprefixed Claude models (#3540) Integrated into release/v3.8.22 — page.tsx conflict resolved (re-applied toggle to ProviderDetailPageClient) + disable-test updated for catalog drift in review. * docs(changelog): credit #3632/#3631/#3637/#3659/#3540/#3616/#3523 (v3.8.22 targeted review round) * fix(mimocode): add required authHeader:"none" to registry entry (#3659 follow-up) The mimocode RegistryEntry omitted the required authHeader field, which broke typecheck:core (TS2741). Match the no-auth convention (authType:"none" + authHeader:"none") used by veoaifree-web and other free providers. Follow-up to #3659 (@pizzav-xyz). * fix(responses): detect stream readiness for tool-call-only and object-less chunks (#3612) (#3661) Closes #3612 * fix(mitm): remove duplicated 'Command failed:' error prefix (#3641) (#3662) Closes #3641 * fix(cli): honor HERMES_HOME for Hermes Agent config path (#3628) (#3663) Closes #3628 * fix(api): fetch live OpenCode model catalog for no-auth model picker (#3611) (#3664) Closes #3611 * fix(api): flag provider topology error state by current status, not stale history (#3619) (#3666) Closes #3619 * fix(electron): launch peer-stamping server-ws.mjs entrypoint to avoid 403 LOCAL_ONLY (#3386) (#3665) Closes #3386 * fix(dashboard): restore home topology live in-flight pulse (#3507) (#3667) Closes #3507 * fix(oauth): name Kiro/AWS auto-imported accounts and dedupe by profileArn (#3615) (#3671) Closes #3615 * fix(resilience): clear stale transient connection cooldowns on startup (#3625) (#3672) Closes #3625 * fix(i18n): use logical CSS direction utilities for sidebar and key overlays (RTL #3541) (#3670) Closes #3541 * fix(dashboard): honor auto-hide and switch to visible filter on passthrough Test-all (#3610) (#3669) Closes #3610 * refactor(dashboard): extract AddApiKeyModal + EditConnectionModal — #3501 Phase 1c (#3674) #3501 Phase 1c: extract AddApiKeyModal, EditConnectionModal, WebSessionCredentialGuide into components/; god-component 10,166->8,092 LOC. Reconciles the v3.8.22 file-size drift for this file. Co-authored-by: oyi77 <oyi77@users.noreply.github.com> * docs(changelog): reconcile v3.8.22 — credit #3621/#3622 + MiMoCode follow-up roll-up * refactor(dashboard): extract ConnectionRow + ModelCompatPopover + SiliconFlowEndpointModal — #3501 Phase 1d (#3676) #3501 Phase 1d: god-component 8,092->6,838 LOC. Co-authored-by: oyi77 <oyi77@users.noreply.github.com> * feat(obsidian): add WebDAV config route + encrypt creds at rest (#3485 part 1) (#3677) Part 1 of #3485. Adds /api/settings/obsidian/webdav (GET/POST/DELETE) wiring the ready obsidianSync lib, encrypts webdav password + obsidian token at rest, removes the duplicate UI block, drops the KNOWN_MISSING entry. WebDAV file server is part 2. * feat(obsidian): add /api/v1/webdav file server for Obsidian vault sync (#3485 part 2) (#3678) Part 2 of #3485. WebDAV server (PROPFIND/GET/PUT/DELETE/MKCOL/MOVE/OPTIONS) handled in the custom server layer (standalone-server-ws.mjs) since the App Router cannot export WebDAV methods. Basic-Auth (constant-time), path-traversal hardened, password decrypt ported from encryption.ts (parity-tested), DATA_DIR resolution parity-tested against dataPaths.ts. End-to-end Obsidian-over-Tailscale validation is a live VPS step (Rule #18). * fix(combo): stop premature context compaction — real auto-combo windows + per-target compression limit (#3680) Integrated into release/v3.8.22 * feat(dashboard): deactivate/activate accounts from the quota overview (#3675) Integrated into release/v3.8.22 * fix(dashboard): close review gaps in bulk provider connection actions (#3271 follow-up) (#3673) Integrated into release/v3.8.22 — page.tsx conflict (god-component split #3501) resolved by re-applying the bulk-action deltas to ProviderDetailPageClient.tsx * refactor(dashboard): extract useModelCompatState hook + model sections — #3501 Phase 1e (#3683) #3501 Phase 1e: extract useModelCompatState hook (unblocks the model sections) + ModelRow/PassthroughModelsSection/PassthroughModelRow/CustomModelsSection/CompatibleModelsSection. god-component 6,838->4,921 LOC. Co-authored-by: oyi77 <oyi77@users.noreply.github.com> * refactor(dashboard): extract useProviderConnections/Settings/Models hooks — #3501 Phase 1f (#3684) #3501 Phase 1f: god-component 4,948->4,062 LOC. Connection state+handlers, settings, and model metadata moved into hooks/. Co-authored-by: oyi77 <oyi77@users.noreply.github.com> * chore(release): v3.8.22 CHANGELOG + env-doc sync - Set release date in CHANGELOG [3.8.22] to 2026-06-11 - Add HERMES_HOME to .env.example (from #3628/#3663) - Add HERMES_HOME + OMNIROUTE_PREFER_CLAUDE_CODE_FOR_UNPREFIXED_CLAUDE_MODELS to ENVIRONMENT.md (#3628/#3540) * docs(changelog): credit #3673 + #3675 — leninejunior bulk-actions + quota-toggle --------- Co-authored-by: oyi77 <oyi77@users.noreply.github.com> Co-authored-by: Abhishek Divekar <adivekar@utexas.edu> Co-authored-by: NOXX - Commiter <artur1992123@mail.ru> Co-authored-by: Nicolas Lorin <androw95220@gmail.com> Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: kkkayye <98376609+kkkayye@users.noreply.github.com> Co-authored-by: Witroch4 <witalo_rocha@hotmail.com> Co-authored-by: Lenine Júnior <lenine@engrene.com.br> |
||
|
|
88857237a2 |
fix(guardrails): use validateBody() in /api/guardrails/test route (#3621)
Replaces request.json() + TestRequestSchema.parse() pattern with the canonical validateBody()/isValidationFailure() pattern from @/shared/validation/helpers, satisfying check:route-validation:t06. |
||
|
|
c315a2394c |
Release v3.8.21 (#3593)
* chore(release): open v3.8.21 development cycle
* fix: pass through valid max_tokens-truncated responses instead of fake 502 (#3572) (#3595)
* fix: /v1/completions returns legacy text-completion format, not chat (#3571) (#3596)
* fix: z.ai/GLM coding plan no longer shows Monthly 0% when no monthly cap (#3580) (#3597)
* docs: mark DISCOVERY_TOOL_DESIGN endpoints as Phase-2 not-yet-implemented (#3498) (#3599)
* fix(agent-bridge): add validate-only upstream-ca/test route (#3488) (#3600)
* fix(gamification): add level/badges/badges-earned profile routes (#3484)
* security(oauth): migrate 5 public client_ids to resolvePublicCred (#3493)
* fix(mcp): ship MCP server source closure in npm files + coverage gate (#3578)
* fix: add reasoning token buffer for combo routing (fixes #3587) (#3588)
Integrated into release/v3.8.21
* Refactor: Extract chatCore phases into modular files (#3598)
Integrated into release/v3.8.21 — chatCore phase modularization. Adjusted: re-derive idempotencyKey for the save path after the check moved into the module (co-authored). Thanks @oyi77!
* docs(changelog): credit #3598 (chatCore modularization) + #3588 (combo reasoning buffer)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(api): implement GET /api/guardrails + POST /api/guardrails/test, drop shadow/guardrails doc-fiction (#3496) (#3602)
Integrated into release/v3.8.21 — implements GET /api/guardrails + POST /api/guardrails/test, removes shadow/guardrails doc-fiction. TDD-validated (5/5) + check-docs-symbols/typecheck/eslint green.
* fix(gemini): isolate textual reasoning wrappers (#3605)
Split-out PR C from #3584. Isolates textual reasoning wrappers (<think>/<thinking>/<thought>/<internal_thought>, including malformed/open tags) into reasoning_content across both the non-streaming sanitizer and the Gemini streaming translator, with split-chunk buffering. Additive to the existing textual tool-call pipeline; does not touch the #3569 native functionResponse path. Integrated into release/v3.8.21. Thanks @dhaern!
* fix(antigravity): normalize Gemini 3.5 Flash tier IDs (#3603)
Split-out PR A from #3584. Normalizes the Antigravity/agy Gemini 3.5 Flash tier IDs to clean public names (gemini-3.5-flash-low/medium/high), maps them to the live upstream IDs at the executor boundary, and removes Antigravity from the global model resolver so the executor owns wire normalization. Maintainer follow-up: kept gemini-3.5-flash-preview as a hidden backward-compat alias routing to the High tier (so saved combos/configs keep working). Live-validated the tier set via the agy CLI catalog. Integrated into release/v3.8.21. Thanks @dhaern!
* fix(agent-bridge): surface real MITM startup-failure cause, not always port 443 (#3606) (#3608)
Integrated into release/v3.8.21 (#3606)
* fix(oauth): surface real Kiro import-token failure cause, not a bare 500 (#3589) (#3609)
Integrated into release/v3.8.21 (#3589)
* docs(opencode-provider): soft-deprecate in favor of @omniroute/opencode-plugin (#3419) (#3613)
Integrated into release/v3.8.21 (#3419)
* fix(usage): normalize Antigravity and agy provider quotas (#3604)
Split-out PR B from #3584. Normalizes Antigravity/agy provider quotas: prefers retrieveUserQuota for live consumption, falls back to fetchAvailableModels and local usage_history, sanitizes cached Provider Limits so retired upstream IDs are not re-exposed, and schedules a deduplicated post-usage refresh. Maintainer follow-up: decoupled the post-usage refresh via a lightweight usageEvents bus (usageHistory no longer dynamic-imports providerLimits) so it does not pull the executors/translator graph into the typecheck-core surface — typecheck:core stays at 0. Integrated into release/v3.8.21. Thanks @dhaern!
* feat(cli): add autostart on/off/toggle shorthand for headless serve mode (#3331) (#3614)
Integrated into release/v3.8.21 (#3331)
* docs(changelog): credit #3603 (Flash tier IDs) + #3604 (provider quotas) + #3605 (reasoning wrappers)
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* fix(review): resolve findings from /review-reviews battery (v3.8.21 hardening) (#3618)
Pre-release hardening from the /review-reviews battery — 15 findings resolved (L1-L13,L15) + L14 live-verified WONTFIX, convergence re-review clean. lint/typecheck:core/test:vitest(146)/build green; zero new test:unit failures vs baseline
|
||
|
|
d6f008cdaf | fix(resilience): expose providerCooldown in GET+PATCH /api/resilience (#3591) | ||
|
|
bf8b56b29f |
Release v3.8.20 (#3547)
* chore(release): open v3.8.20 development cycle * fix(images): prefer bare combos over image aliases (#3527) Integrated into release/v3.8.20 * fix(translator): map Codex local_shell tool (#3534) Integrated into release/v3.8.20 * fix(usage): make opencode-go quota fetcher fail-open instead of throwing 500 (#3522) Integrated into release/v3.8.20 * Fix Runtime page breaker state rendering (#3533) Integrated into release/v3.8.20 * Expose provider breaker degradation threshold setting (#3535) Integrated into release/v3.8.20 * fix(executor): strip provider prefix from versioned built-in tool model field (#3532) Integrated into release/v3.8.20 * feat(providers): add Claude Fable 5 support (#3524) Integrated into release/v3.8.20 * feat(resilience): add global provider cooldown tracking to prevent combo re-walking (#3556) Integrated into release/v3.8.20 (default OFF, opt-in) * fix(translator): scope thoughtSignature bypass to Antigravity/CLI only (#3560) Integrated into release/v3.8.20. Co-authored-by: Six7Day <six7day@gmail.com> * fix(routing): normalize thinking:disabled for combo-substituted models that reject it (#3554) (#3563) Integrated into release/v3.8.20 * fix(usage): accept 0/empty budget limits so the dashboard can save and clear (#3537) (#3564) Integrated into release/v3.8.20 * docs(changelog): credit @Six7Day for #3560 thoughtSignature fix (#3414) The #3560 squash co-author trailer landed inline (unparsed by GitHub), so add an explicit CHANGELOG credit ensuring @Six7Day (original #3414) and @oyi77 are on the public record for the Gemini thoughtSignature fix. * fix(gamification): dedup badge unlock via user_badges so events don't re-fire every request (#3472) (#3565) Integrated into release/v3.8.20 * fix(routing): pass through 'auto' keyword on codex /v1/responses instead of rewriting to codex/auto (#3509) (#3566) Integrated into release/v3.8.20 * fix(cli-tools): normalize apiKey null in guide-settings schema so cloud-mode config saves (#3552) (#3567) Integrated into release/v3.8.20 * fix(catalog): reclassify PublicAI from keyless to one-time-initial (requires API key) (#3558) (#3568) Integrated into release/v3.8.20 * fix(gemini-web): surface missing Playwright browser as actionable 503 + cooldown hint, not a retryable 500 loop (#3516) (#3570) Integrated into release/v3.8.20 * fix(security): sanitize raw err.message in web executors + embeddings/search response bodies (Rule #12) (#3494, #3495) (#3573) Integrated into release/v3.8.20 * fix(dashboard): point CustomHostsManager + FeatureFlagsGrid at real routes (#3486, #3487) (#3574) Integrated into release/v3.8.20 * chore(providers): remove dead krutrim entry (#3483) + docs(api): fix agent-bridge per-agent state route (#3489) (#3575) Integrated into release/v3.8.20 * docs(api): correct API_REFERENCE.md paths for skills/plugins/admin/cache/acp/system-info (#3497) (#3577) Integrated into release/v3.8.20 * fix(proxy): drive SOCKS5 UI option from runtime ENABLE_SOCKS5_PROXY, not build-time NEXT_PUBLIC (#3508) (#3579) Integrated into release/v3.8.20 * fix(playground): filter playground models by node prefix so custom-endpoint models appear (#3505) (#3581) Integrated into release/v3.8.20 * fix(usage): show an informative message instead of a blank Kiro quota card when no usage breakdown (#3506) (#3582) Integrated into release/v3.8.20 * docs(changelog): add the #3506 Kiro quota entry (missed in #3582 due to a stale-base CHANGELOG anchor) (#3583) Integrated into release/v3.8.20 * fix(auto-update): use stable PROJECT_ROOT walker, not frozen process.cwd() (#3561) Integrated into release/v3.8.20. Auto-update PROJECT_ROOT now uses a stable __dirname-anchored upward walker instead of the no-op process.cwd() resolver. * fix: address PR #3518 review comments (lifecycle hooks, regex, indentation, route params) (#3562) Integrated into release/v3.8.20. Addresses #3518 review: regex literals, logs/[id] route params (Next 16), indentation, and wires plugin lifecycle hooks (onInstall/onActivate/onDeactivate/onUninstall) in the loader so manager.ts can register them. Adds Rule #18 regression test. * docs(changelog): credit @ViFigueiredo (#3423) for PROJECT_ROOT + log #3561/#3562 (v3.8.20) * fix: openai to gemini incorrectly translates historical tool calls into text (#3569) Integrated into release/v3.8.20. Standard Gemini direct path now maps historical tool calls to native functionCall/functionResponse parts (signaturelessToolCallMode: native) instead of inert text — validated against the real Gemini API (gemini-2.5-flash returns 200 for signatureless native functionCall, even with tools+thinking; Hard Rule #18). Eliminates the text-serialization leak. Antigravity/CLI sentinel path (#3560) untouched. * docs(changelog)+test: reconcile standard-Gemini native mode (#3569) — update round-2 rationale comment + log VPS validation * docs(changelog): reconcile v3.8.20 — add 9 missing bullets + move [Unreleased] to versioned section * docs(changelog): complete v3.8.20 reconciliation — 27 bullets, 11 contributors --------- Co-authored-by: Alexander Averyanov <alex@averyan.ru> Co-authored-by: Hakan Kurşun <bykamaka@gmail.com> Co-authored-by: Wilson <pedbookmed@gmail.com> Co-authored-by: Randi <55005611+rdself@users.noreply.github.com> Co-authored-by: Giorgos Giakoumettis <giorgos@yiakoumettis.gr> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: Markus Hartung <mail@hartmark.se> |
||
|
|
8169b97d84 |
Release v3.8.18 (#3482)
* chore(release): open v3.8.18 development cycle * fix(catalog): stop Codex CLI model-catalog refresh from erroring (#3481) Codex's model-catalog refresh (codex_models_manager) does GET /v1/models?client_version=<v> and decodes a JSON object with a TOP-LEVEL `models` array. OmniRoute answers in the OpenAI-standard `{object,data}` shape, so codex fails with "missing field `models`" and logs "failed to refresh available models" on every startup. Detect codex clients via the `originator` / `user-agent` = `codex_*` headers they send and add an EMPTY top-level `models: []` so the decode succeeds. Non-codex OpenAI clients keep the byte-identical `{object,data}` response. The array is intentionally empty: codex replaces its built-in per-model agent prompt (`base_instructions`, ~21k chars) with whatever a populated entry carries for the selected model, so emitting our catalog would drop the agent prompt to nothing and break codex's agent behaviour (verified empirically against codex 0.137). An empty list keeps codex on its built-in model info — same inference as before, minus the error. Validated end-to-end with the real handler against codex 0.137: "failed to refresh available models" → 0 occurrences, instructions preserved (built-in Codex agent prompt, not empty). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: ignore quality reports and local prompt artifacts Add generated quality gate reports, metrics files, and local setup prompt artifacts to .gitignore to prevent committing environment-specific or temporary files. * fix(provider): detect Responses API format when body has `input` but … (#3490) Integrated into release/v3.8.18 * fix(sse): normalize numeric provider ids to strings (#3451) Integrated into release/v3.8.18 * feat(browserPool): resolve Playwright proxy from proxy_registry DB (#3492) Integrated into release/v3.8.18 * fix(theoldllm): generate X-Request-Token server-side, drop Playwright (#3491) Integrated into release/v3.8.18 * feat(plugins): add lifecycle hooks and theme-manager plugin (#3473) Integrated into release/v3.8.18 * fix(combo): parallel pre-screen + circuit-breaker fast-exit for priority combos (#3169) Integrated into release/v3.8.18 * feat(ui): unifi active and finished requests into single view #1422 (#3401) Integrated into release/v3.8.18 * docs(changelog): record #3401, #3473, #3492, #3490, #3451, #3491, #3169 under v3.8.18 * feat(docs): add doc accuracy gate + refresh AGENTS.md counts (#3510) Integrated into release/v3.8.18 * fix(sse): drop empty-choices chunks without usage instead of injecting retry text (#3513) PR #3422 ('allow OpenAI usage-only empty choices chunks') reintroduced the assistant-content injection '[OmniRoute] Upstream returned an empty response. Please retry.' for empty `choices: []` chunks that carry no valid usage. Clients (Goose/opencode) feed that text back as a turn and spin in a retry loop -- the exact regression #3400 had fixed by dropping the chunk. Restore the drop behavior for the no-usage case while preserving #3422's standards-compliant forwarding of usage-only `include_usage` final chunks. Realign the mislabeled stream-utils test (it asserted the injection) and add a dedicated regression guard. Reported-by: @mochizzan Refs: #3502, #3388, #3400, #3422 * fix(authz): fall back to URL token when Authorization isn't a usable Bearer (#3504) Integrated into release/v3.8.18 * fix(playground): authenticate via session, test key policy by id (#3503) Integrated into release/v3.8.18 * docs(changelog): record #3510, #3504, #3503 under v3.8.18 * fix: llama base url normalization (#3519) * docs(changelog): reconcile v3.8.18 — add #3519, #3513, #3435-repair, gitignore chore (full commit↔changelog coverage) * fix(opencode-plugin): bound regex quantifiers in normaliseFreeLabel (polynomial-ReDoS) CodeQL js/polynomial-redos: unbounded \s* before an anchored \s*$ allowed O(n²) backtracking on attacker-influenced display names. Bounded to {0,8}/{1,8} (ample for any real label spacing). Plugin builds + 254 tests green. * fix(types): restore clean typecheck:core for v3.8.18 release gate - getPendingRequests() typed to real shape (was widened to object) → fixes unknown 'count' in the unified-requests view (#3401) - streamChunks log payload cast to its declared type (callLogs.ts) - preScreenTargets aligned to canonical IsModelAvailable signature (#3169), Promise.resolve-normalized so .catch never hits a bare boolean All 5 gates green: lint(0 err) + typecheck:core + cycles + docs-all + unit + vitest(146). --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Andrey Borodulin <borodulin@gmail.com> Co-authored-by: Dmitrii Safronov <zimniy@cyberbrain.cc> Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com> Co-authored-by: PizzaV <103120356+pizzav-xyz@users.noreply.github.com> Co-authored-by: Markus Hartung <mail@hartmark.se> Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com> |
||
|
|
500197846d |
Add model catalog name feature flag (#3464)
Integrated into release/v3.8.17 |
||
|
|
5c3545b045 |
Add Endpoint Token Saver visibility setting (#3461)
Integrated into release/v3.8.17 |
||
|
|
4f38167964 |
fix(catalog): surface imported models on no-auth providers in /api/v1/models (#3200) (#3463)
The custom-models loop in getUnifiedModelsResponse gated every model through hasEligibleConnectionForModel(getConnectionsForProvider(...)). no-auth providers (theoldllm, etc.) never create DB connection rows, so that returned [] and the gate dropped every imported/custom model for them — the Playground dropdown showed nothing for imported models while built-in/custom models on auth providers worked. Built-in models survived because they go through providerSupportsModel(), which already has a no-auth bypass (#2798). The custom-model gate now applies the same no-auth bypass, keeping the eligibility check (with parentProviderType) intact for auth providers. Co-authored-by: tjengbudi <tjengbudi@users.noreply.github.com> Co-authored-by: a2belugin <a2belugin@users.noreply.github.com> |
||
|
|
42887b65b2 |
feat: add connection pagination, health filter, batch delete confirmation, and custom banned keywords (#3454)
Integrated into release/v3.8.17 |
||
|
|
003e6a80b7 |
feat(plugin+api): auto combos + free model quota display + /api/combos/auto (#3435)
Integrated into release/v3.8.17 |
||
|
|
617a648088 |
fix(translator): use non-empty reasoning_content placeholder on cache miss instead of empty string (#3433)
Integrated into release/v3.8.17 |
||
|
|
a00366602b |
docs: close critical documentation gaps (ACP, router strategies, APIs, compression) (#3438)
Integrated into release/v3.8.17 |
||
|
|
1e4185edac |
fix(analytics): scope SQL named params per query context (#3446) (#3447)
Integrated into release/v3.8.17 |
||
|
|
b3372e46c4 |
fix(command-code): revert chat endpoint to /alpha/generate and fix model sync discovery (#3432)
Integrated into release/v3.8.17 |
||
|
|
6ec4ca3f67 |
ci: speed up e2e shards with build and browser cache
Upload the Next.js build from the build job and reuse it across E2E shards to avoid rebuilding in each shard. Increase Playwright sharding from 6 to 9, cache Chromium browsers, and lower the E2E timeout to match the faster expected runtime. Add a Codex CLI configuration skill for OmniRoute setup and ignore local credential-bearing setup prompts. |
||
|
|
e328e257d1 |
fix(docs+ui): add MDX frontmatter to Codex CLI guide, fix setState-in-effect lint
- docs/guides/CODEX-CLI-CONFIGURATION.md was missing the YAML frontmatter block required by fumadocs (title/version/lastUpdated), causing the production build to fail with "invalid frontmatter" MDX error. - CodexCliGuideModal.tsx called setLoading/setError synchronously in a useEffect body, triggering the react-hooks/set-state-in-effect lint error. Refactored to an internal async function with an `cancelled` guard to prevent state updates on unmounted components. |
||
|
|
fd6a2a7f95 |
docs: add Codex CLI configuration guide for OmniRoute
Add a comprehensive guide for configuring Codex CLI to use OmniRoute as an OpenAI-compatible backend. Document ready-to-use config examples, Responses API routing behavior, context window settings, token limits, model profiles, and troubleshooting guidance to help users avoid direct-provider compatibility issues. |
||
|
|
ecdd5a36eb |
feat: add REST API for session pool health (dashboard interface) (#3404)
Integrated into release/v3.8.16 |
||
|
|
71f6e8d312 |
feat: add bulk web-session credential import endpoint (#3403)
Integrated into release/v3.8.16 |
||
|
|
48ed42c6c3 |
fix(providers): refresh model list after provider sync (#3402)
Integrated into release/v3.8.16 |
||
|
|
5b72dc6250 |
feat: adaptive keepalive threshold for web-session providers (#3397)
Integrated into release/v3.8.16 |