fix(release): close final v3.8.50 reconciliation gaps (#8875)

This commit is contained in:
diegosouzapw
2026-08-23 20:12:02 -03:00
parent d2d64bd2f3
commit 673b2947b3
80 changed files with 1667 additions and 904 deletions

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -43,6 +43,21 @@ const suggestSchema = [
},
];
const TASK_TYPES = ["coding", "review", "planning", "analysis", "debugging", "documentation"];
function normalizeTaskType(value) {
const normalized = String(value || "")
.trim()
.toLowerCase();
if (TASK_TYPES.includes(normalized)) return normalized;
if (/debug|bug|error|fix/.test(normalized)) return "debugging";
if (/review|audit/.test(normalized)) return "review";
if (/plan|architect|design/.test(normalized)) return "planning";
if (/doc|readme|guide/.test(normalized)) return "documentation";
if (/code|implement|program/.test(normalized)) return "coding";
return "analysis";
}
export function extendComboSuggest(combo) {
combo
.command("suggest")
@@ -50,29 +65,28 @@ export function extendComboSuggest(combo) {
.requiredOption("--task <description>", t("combo.suggest.task"))
.option("--max-cost <usd>", t("combo.suggest.maxCost"), parseFloat)
.option("--max-latency-ms <ms>", t("combo.suggest.maxLatencyMs"), parseInt)
.option("--weights <json>", t("combo.suggest.weights"))
.option("--top <n>", t("combo.suggest.top"), parseInt, 5)
.option("--explain", t("combo.suggest.explain"))
.option("--switch", t("combo.suggest.switch"))
.action(async (opts, cmd) => {
const body = {
task: opts.task,
constraints: {
maxCostUsd: opts.maxCost,
maxLatencyMs: opts.maxLatencyMs,
},
weights: opts.weights ? JSON.parse(opts.weights) : undefined,
top: opts.top,
taskType: normalizeTaskType(opts.task),
budgetConstraint: opts.maxCost,
latencyConstraint: opts.maxLatencyMs,
};
const data = await mcpCallTool("omniroute_best_combo_for_task", body);
const candidates = data.candidates ?? data;
const rows = (Array.isArray(candidates) ? candidates : []).map((c, i) => ({
const candidates = data.recommendedCombo
? [data.recommendedCombo, ...(Array.isArray(data.alternatives) ? data.alternatives : [])]
: (data.candidates ?? data);
const rows = (Array.isArray(candidates) ? candidates : []).slice(0, opts.top).map((c, i) => ({
rank: i + 1,
...c,
}));
emit(rows, cmd.optsWithGlobals(), suggestSchema);
if (opts.explain && !cmd.optsWithGlobals().quiet) {
process.stderr.write(`\nRationale:\n${data.rationale ?? "(no rationale)"}\n`);
process.stderr.write(
`\nRationale:\n${data.recommendedCombo?.reason ?? data.rationale ?? "(no rationale)"}\n`
);
}
if (opts.switch && rows[0]) {
const best = rows[0].name;

View File

@@ -107,21 +107,35 @@ export async function runCompressionStatus(opts, cmd) {
export async function runCompressionConfigure(opts, cmd) {
const config = {};
// #6571 — both the MCP tool schema (compressionConfigureInput) and
// handleCompressionConfigure expect `strategy`, not `engine`; a non-strict
// MCP schema silently strips an unrecognized `engine` key on the primary
// (MCP-mounted) path, so this must be `strategy` on both paths.
if (opts.engine) config.strategy = normalizeEngine(opts.engine);
if (opts.cavemanAggressiveness !== undefined)
config.caveman = { aggressiveness: opts.cavemanAggressiveness };
if (opts.rtkBudget !== undefined) config.rtk = { tokenBudget: opts.rtkBudget };
if (opts.languagePack) config.languagePack = opts.languagePack;
// Keep this payload byte-for-byte within compressionConfigureInput. Engine-
// specific Caveman/RTK controls belong to `compression engine set`, whose
// MCP tool has a different schema.
const strategy = opts.strategy ?? opts.engine;
if (strategy) config.strategy = normalizeEngine(strategy);
for (const key of [
"enabled",
"autoTriggerMode",
"maxTokens",
"targetRatio",
"preserveSystemPrompt",
"mcpDescriptionCompressionEnabled",
]) {
if (opts[key] !== undefined) config[key] = opts[key];
}
const data = await mcpCall("omniroute_compression_configure", config, () =>
restCompressionConfigure(config)
);
emit(data, cmd.optsWithGlobals());
}
export async function runCompressionComboStats(opts, cmd) {
const since = opts.period ?? "7d";
const data = await mcpCall("omniroute_compression_combo_stats", { since }, () =>
restComboStats(since)
);
emit(data, cmd.optsWithGlobals());
}
export async function runCompressionEngineSet(name, opts, cmd) {
const normalized = normalizeEngine(name);
if (!VALID_ENGINES.includes(normalized)) {
@@ -161,10 +175,21 @@ export function registerCompression(program) {
cmp
.command("configure")
.description(t("compression.configure.description"))
.option("--engine <e>", t("compression.configure.engine"))
.option("--caveman-aggressiveness <n>", t("compression.configure.caveman_agg"), parseFloat)
.option("--rtk-budget <n>", t("compression.configure.rtk_budget"), parseInt)
.option("--language-pack <p>", t("compression.configure.language_pack"))
.option("--strategy <mode>", t("compression.configure.engine"))
.option("--enabled <boolean>", "Enable or disable compression", (value) => value === "true")
.option("--auto-trigger-mode <mode>", "Compression mode used by automatic triggering")
.option("--max-tokens <n>", "Maximum tokens before compression triggers", parseInt)
.option("--target-ratio <n>", "Target compression ratio (0.0-1.0)", parseFloat)
.option(
"--preserve-system-prompt <boolean>",
"Preserve the system prompt",
(value) => value === "true"
)
.option(
"--mcp-description-compression-enabled <boolean>",
"Compress MCP tool descriptions",
(value) => value === "true"
)
.action(runCompressionConfigure);
const engine = cmp.command("engine").description(t("compression.engine.description"));
@@ -181,17 +206,7 @@ export function registerCompression(program) {
}));
emit(data.combos ?? data, cmd.optsWithGlobals());
});
combos
.command("stats")
.option("--period <p>", null, "7d")
.action(async (opts, cmd) => {
const data = await mcpCall(
"omniroute_compression_combo_stats",
{ period: opts.period ?? "7d" },
() => restComboStats(opts.period)
);
emit(data, cmd.optsWithGlobals());
});
combos.command("stats").option("--period <p>", null, "7d").action(runCompressionComboStats);
const rules = cmp.command("rules").description(t("compression.rules.description"));
rules.command("list").action(async (opts, cmd) => {

View File

@@ -1,5 +1,6 @@
import { readFileSync } from "node:fs";
import { apiFetch, isServerUp } from "../api.mjs";
import { mcpCallTool } from "../mcpClient.mjs";
import { emit } from "../output.mjs";
import { t } from "../i18n.mjs";
@@ -61,10 +62,15 @@ export function registerMcp(program) {
? JSON.parse(argsPositional)
: {};
const exitCode = await runMcpCallCommand(tool, args, {
...opts,
stream: opts.stream,
}, globalOpts);
const exitCode = await runMcpCallCommand(
tool,
args,
{
...opts,
stream: opts.stream,
},
globalOpts
);
if (exitCode !== 0) process.exit(exitCode);
});
@@ -86,130 +92,25 @@ export function registerMcp(program) {
});
}
/**
* Shared JSON-RPC 2.0 MCP client used by both stream and non-stream `mcp call`.
*
* Protocol:
* 1. POST /api/mcp/stream with initialize → get Mcp-Session-Id header
* 2. POST /api/mcp/stream with tools/call + Mcp-Session-Id header
*
* When `stream` is true, writes SSE data chunks to stdout as they arrive.
* When `stream` is false, returns the parsed JSON-RPC result.
*
* Returns the exit code (0 = success, non-zero = failure).
*/
async function mcpJsonRpcCall(tool, args, { stream = false, globalOpts = {} } = {}) {
const baseUrl = globalOpts.baseUrl ?? "http://localhost:20128";
const apiKey = globalOpts.apiKey ?? "";
const streamUrl = `${baseUrl}/api/mcp/stream`;
const hdrs = {
"Content-Type": "application/json",
Accept: stream ? "text/event-stream" : "application/json",
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
};
// Step 1 — initialize
const initRes = await fetch(streamUrl, {
method: "POST",
headers: hdrs,
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "initialize",
params: {
protocolVersion: "2024-11-05",
capabilities: {},
clientInfo: { name: "omniroute-cli", version: "1.0" },
},
}),
});
if (!initRes.ok) {
const text = await initRes.text().catch(() => "");
process.stderr.write(`MCP initialize failed: HTTP ${initRes.status}${text ? `${text}` : ""}\n`);
return 1;
}
const sessionId = initRes.headers.get("mcp-session-id");
if (!sessionId) {
process.stderr.write("MCP initialize failed: no Mcp-Session-Id in response\n");
return 1;
}
// Step 2 — tools/call
const callHeaders = {
...hdrs,
"mcp-session-id": sessionId,
};
const callRes = await fetch(streamUrl, {
method: "POST",
headers: callHeaders,
body: JSON.stringify({
jsonrpc: "2.0",
id: 2,
method: "tools/call",
params: { name: tool, arguments: args },
}),
});
if (!callRes.ok) {
const text = await callRes.text().catch(() => "");
process.stderr.write(`MCP call failed: HTTP ${callRes.status}${text ? `${text}` : ""}\n`);
return 1;
}
if (stream) {
return readMcpSseStream(callRes.body);
}
// Non-stream: parse JSON-RPC response
const data = await callRes.json();
if (data.error) {
process.stderr.write(`MCP error: ${data.error.message || JSON.stringify(data.error)}\n`);
return 1;
}
// Print the result content
const content = data.result?.content;
if (content) {
for (const item of content) {
if (item.type === "text") {
process.stdout.write(item.text + "\n");
} else if (item.type === "resource") {
process.stdout.write(JSON.stringify(item.resource) + "\n");
} else {
process.stdout.write(JSON.stringify(item) + "\n");
}
}
} else {
process.stdout.write(JSON.stringify(data.result, null, 2) + "\n");
}
return 0;
}
async function readMcpSseStream(body) {
if (!body) return 1;
const reader = body.getReader();
const dec = new TextDecoder();
let buf = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buf += dec.decode(value, { stream: true });
}
const lines = buf.split("\n");
for (const line of lines) {
if (line.startsWith("data: ")) {
const raw = line.slice(6).trim();
if (raw && raw !== "[DONE]") process.stdout.write(raw + "\n");
}
}
return 0;
}
export async function runMcpCallCommand(tool, args, opts = {}, globalOpts = {}) {
return mcpJsonRpcCall(tool, args, { stream: opts.stream, globalOpts });
try {
const result = await mcpCallTool(tool, args, {
...globalOpts,
...opts,
stream: opts.stream === true,
timeout: opts.timeout ?? globalOpts.timeout,
});
if (!opts.stream) {
if (typeof result === "string") process.stdout.write(`${result}\n`);
else emit(result, globalOpts);
}
return 0;
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
process.stderr.write(`MCP call failed: ${message}\n`);
return typeof err?.exitCode === "number" ? err.exitCode : 1;
}
}
export async function runMcpStatusCommand(opts = {}) {

View File

@@ -26,48 +26,47 @@ const proxySchema = [
{ key: "state", header: "State" },
];
export async function runOneproxyStats(_opts, cmd) {
const data = await mcpCall("omniroute_oneproxy_stats", {});
emit(data, cmd.optsWithGlobals());
}
export async function runOneproxyFetch(opts, cmd) {
const data = await mcpCall("omniroute_oneproxy_fetch", {
limit: opts.count,
protocol: opts.type,
...(opts.countryCode ? { countryCode: opts.countryCode } : {}),
...(opts.minQuality !== undefined ? { minQuality: opts.minQuality } : {}),
});
emit(data.items ?? data, cmd.optsWithGlobals(), proxySchema);
}
export async function runOneproxyRotate(opts, cmd) {
const data = await mcpCall("omniroute_oneproxy_rotate", {
...(opts.strategy ? { strategy: opts.strategy } : {}),
});
emit(data, cmd.optsWithGlobals());
}
export function registerOneProxy(program) {
const op = program.command("oneproxy").description(t("oneproxy.description"));
op.command("status").action(async (opts, cmd) => {
const data = await mcpCall("omniroute_oneproxy_stats", {});
emit(data, cmd.optsWithGlobals());
});
op.command("status").action(runOneproxyStats);
op.command("stats")
.option("--provider <p>", t("oneproxy.stats.provider"))
.option("--period <p>", t("oneproxy.stats.period"), "24h")
.action(async (opts, cmd) => {
const data = await mcpCall("omniroute_oneproxy_stats", {
provider: opts.provider,
period: opts.period,
});
emit(data, cmd.optsWithGlobals());
});
op.command("stats").action(runOneproxyStats);
op.command("fetch")
.description(t("oneproxy.fetch.description"))
.option("--count <n>", t("oneproxy.fetch.count"), parseInt, 1)
.option("--type <t>", t("oneproxy.fetch.type"), "http")
.action(async (opts, cmd) => {
const data = await mcpCall("omniroute_oneproxy_fetch", {
count: opts.count,
type: opts.type,
});
emit(data.proxies ?? data, cmd.optsWithGlobals(), proxySchema);
});
.option("--country-code <code>", "Filter by country code")
.option("--min-quality <n>", "Minimum quality score (0-100)", parseFloat)
.action(runOneproxyFetch);
op.command("rotate")
.description(t("oneproxy.rotate.description"))
.option("--provider <p>", t("oneproxy.rotate.provider"))
.option("--connection-id <id>", t("oneproxy.rotate.connectionId"))
.action(async (opts, cmd) => {
const data = await mcpCall("omniroute_oneproxy_rotate", {
provider: opts.provider,
connectionId: opts.connectionId,
});
emit(data, cmd.optsWithGlobals());
});
.option("--strategy <strategy>", "Rotation strategy: random, quality, or sequential")
.action(runOneproxyRotate);
const config = op.command("config").description(t("oneproxy.config.description"));

View File

@@ -143,7 +143,7 @@ export async function runSkillsExecute(id, opts, cmd) {
const data = await mcpCallTool(
"omniroute_skills_execute",
{ skillId: id, input },
{ timeout: opts.timeout ?? 30000 },
{ timeout: opts.timeout ?? 30000 }
);
emit(data, globalOpts);
}

View File

@@ -20,20 +20,24 @@ function mcpError(message, status) {
return err;
}
async function callMcpEndpoint(payload, { timeout, stream }) {
async function callMcpEndpoint(payload, { timeout, stream, headers = {}, ...apiOptions }) {
const res = await apiFetch("/api/mcp/stream", {
...apiOptions,
method: "POST",
body: payload,
timeout,
acceptNotOk: true,
headers: stream ? { Accept: "text/event-stream" } : {},
headers: {
...(stream ? { Accept: "text/event-stream" } : {}),
...headers,
},
});
if (!res.ok) {
const text = await res.text().catch(() => "");
throw mcpError(
`${payload.method} ${payload.id}: HTTP ${res.status}${text ? `${text}` : ""}`,
res.status,
res.status
);
}
return res;
@@ -46,7 +50,7 @@ async function callMcpEndpoint(payload, { timeout, stream }) {
* Stream: writes SSE `data:` chunks to stdout and returns null on success.
*/
export async function mcpCallTool(name, args = {}, options = {}) {
const { timeout, scope } = options;
const { scope, stream, onChunk, ...apiOptions } = options;
const scopeHeader = scope?.length ? { "X-MCP-Scopes": scope.join(",") } : {};
const initRes = await callMcpEndpoint(
@@ -60,7 +64,7 @@ export async function mcpCallTool(name, args = {}, options = {}) {
clientInfo: { name: "omniroute-cli", version: "1.0" },
},
},
{ timeout, stream: options.stream },
{ ...apiOptions, stream, headers: scopeHeader }
);
const sessionId = initRes.headers.get("mcp-session-id");
@@ -75,11 +79,15 @@ export async function mcpCallTool(name, args = {}, options = {}) {
method: "tools/call",
params: { name, arguments: args },
},
{ timeout, stream: options.stream },
{
...apiOptions,
stream,
headers: { ...scopeHeader, "mcp-session-id": sessionId },
}
);
if (options.stream) {
return consumeSse(callRes.body, options.onChunk);
if (stream) {
return consumeSse(callRes.body, onChunk);
}
const data = await callRes.json();
@@ -92,7 +100,25 @@ export async function mcpCallTool(name, args = {}, options = {}) {
const msg = data.result?.content?.[0]?.text || "unknown tool error";
throw mcpError(`MCP error: ${msg}`, 500);
}
return data.result;
return decodeToolResult(data.result);
}
function decodeToolResult(result) {
if (!result || typeof result !== "object") return result;
if (result.structuredContent && typeof result.structuredContent === "object") {
return result.structuredContent;
}
const textItems = Array.isArray(result.content)
? result.content.filter((item) => item?.type === "text" && typeof item.text === "string")
: [];
if (textItems.length !== 1) return result;
try {
return JSON.parse(textItems[0].text);
} catch {
return textItems[0].text;
}
}
async function consumeSse(body, onChunk) {

View File

@@ -1 +0,0 @@
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282))

View File

@@ -1 +0,0 @@
- **fix(ollama):** Ollama Local models are no longer flattened to `chat` at sync time — the synced store persists every advertised capability and chat filtering moves to read time, so `/v1/embeddings` and `/v1/images/generations` stop rejecting models the daemon reports as capable ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271)) — thanks @yourspraveen

View File

@@ -4733,7 +4733,7 @@
},
"tests/unit/cli-mcp-call-commands.test.ts": {
"@typescript-eslint/no-explicit-any": {
"count": 16
"count": 14
}
},
"tests/unit/cli-memory-commands.test.ts": {

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -302,6 +302,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -836,7 +838,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1066,7 +1067,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1170,7 +1171,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1232,6 +1232,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1520,6 +1525,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1530,7 +1536,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1558,7 +1564,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1621,7 +1627,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1653,12 +1659,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1671,6 +1678,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1699,7 +1707,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1765,9 +1773,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -300,6 +300,8 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **feat(providers):** allow overriding the rate-limit queue wait timeout (`maxWaitMs`) per connection, alongside the existing `rpm`/`tpm`/`tpd`/`minTime`/`maxConcurrent` overrides — a single slow provider no longer has to lower the global wait budget for every other provider ([#11251](https://github.com/diegosouzapw/OmniRoute/pull/11251) — thanks @maxmad64bis)
- **feat(monitoring):** expose the structural chat-admission snapshot through the health API and count capacity sheds by `queue_timeout` or `queued_bytes_budget`, with one credential-safe structured warning per shed and aborted waits excluded; admission behavior and thresholds are unchanged ([#11268](https://github.com/diegosouzapw/OmniRoute/pull/11268) — thanks @backryun) (reported in [#11244](https://github.com/diegosouzapw/OmniRoute/issues/11244) — thanks @im-ecorp)
- **feat(catalog):** surface runtime-learned `reasoning_effort` tiers in `/v1/models` `capabilities.effort_tiers` (learned set replaces synced metadata when present), map them to OpenCode `ModelV2.variants` in the OmniRoute plugin, and align dispatch `-<tier>` suffix validation to the effective (learned ?? synced) set — so the UI offers exactly the tiers the upstream accepts (e.g. `{low, high, max}` for `oc/x-preview-f-free`) and each advertised variant completes. Excludes codex/glm/kimi, which keep their own dedicated `-{effort}` suffix mechanism and never gain `effort_tiers` from this path ([#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232), [#11252](https://github.com/diegosouzapw/OmniRoute/pull/11252) — thanks @maxmad64bis) (reported in [#7694](https://github.com/diegosouzapw/OmniRoute/issues/7694) — thanks @excessivechaos)
- **feat(vertex):** discover Anthropic partner models from the Vertex AI Model Garden's PublisherModels API and route dynamically discovered `claude-*` IDs through the Claude translator for both `vertex` and `vertex-partner` ([#11279](https://github.com/diegosouzapw/OmniRoute/pull/11279) — thanks @maci0; integration test by @hartmark)
- **feat(dashboard):** replace the hard Home → onboarding redirect with a dismissable first-run readiness card so returning users can stay on Home while new users still get a clear 4-step path; Pitch #03 is tracked in [#11167](https://github.com/diegosouzapw/OmniRoute/issues/11167) ([#11282](https://github.com/diegosouzapw/OmniRoute/pull/11282) — thanks @ignamiranda)
### 🐛 Bug Fixes
@@ -834,7 +836,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** preserve validator HTTP status codes in API-key and web connection-test results so callers can distinguish authentication, rate-limit, and upstream failures ([#10272](https://github.com/diegosouzapw/OmniRoute/pull/10272)) — thanks @Zartharas
- **fix(sse):** tiny-budget reasoning probes (e.g. Claude Code's `/model` check sends `max_tokens: 1`) are answered with a valid truncated 200 instead of relaying the upstream 5xx "empty response content" — which previously also marked the connection unavailable and poisoned fallback/cooldown bookkeeping for a request that is only a probe ([#10281](https://github.com/diegosouzapw/OmniRoute/issues/10281)) — thanks @harkaranbrar7
- fix(video): stop advertising the googleflow (Veo) video provider as working and fail fast with a clear diagnostic — its submit/poll endpoints 404 and no server-side OAuth transport can satisfy the working endpoint (#10285)
- fix(sse): mark gemini-3.5-flash as thinking-capable so reasoning_effort is no longer rejected with a spurious 400 (#10286)
- **fix(docker):** prefix cache mount ids with Railway service scope ([#10288](https://github.com/diegosouzapw/OmniRoute/pull/10288)) — thanks @anudeepadi
- **fix(build):** stop Turbopack from dead-code-eliminating the Windows Tailscale branches of `src/lib/tailscaleTunnel.ts` in the published build (#10293). The release `dist` is bundled on a Linux runner, and the bundler constant-folds `process.platform`, pruning every non-Linux branch — the Windows installers shipped with no `where` lookup, an always-injected `--socket`, and a lost `net start Tailscale`/windows-default-binary path. The module now reads the platform at runtime via `os.platform()` (a function call a bundler cannot fold), so the Windows branches survive on any build machine; a vitest regression test mocking `os.platform()``win32` guards the anti-fold invariant (RED before, GREEN after).
- **fix(ops):** Docker HEALTHCHECK defaults to the lightweight `/healthz` lifecycle probe instead of the heavy `/api/monitoring/health` path, with an `OMNIROUTE_HEALTHCHECK_PATH` opt-in override ([#10311](https://github.com/diegosouzapw/OmniRoute/pull/10311))
@@ -1064,7 +1065,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(providers):** route terminal `testStatus` writes (`banned`, `deactivated`, `credits_exhausted`) through a single origin-aware passage — probe failures are recorded but never deactivate the connection ([#11009](https://github.com/diegosouzapw/OmniRoute/pull/11009)) — thanks @maxmad64bis
- **fix(codex):** drop non-standard `codex.*` SSE events by default so OpenAI SDK / Codex CLI `/v1/responses` clients are not 502'd by `event: codex.rate_limits` ([#11014](https://github.com/diegosouzapw/OmniRoute/issues/11014)) — thanks @RaviTharuma
- **fix(resilience):** count heavyweight `/v1` admission leases in the SIGTERM drain and send `Retry-After` on shutdown 503s so Recreate no longer looks like an empty 502 ([#11015](https://github.com/diegosouzapw/OmniRoute/issues/11015)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016)) — thanks @RaviTharuma
- **fix(startup):** log `Credential health scheduler disabled` when `OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK` is set instead of lying with `started` ([#11016](https://github.com/diegosouzapw/OmniRoute/issues/11016) — thanks @RaviTharuma); pin the real disabled-boot output with subprocess regression coverage ([#11265](https://github.com/diegosouzapw/OmniRoute/pull/11265) — thanks @Prajeeth-12)
- **docs(api-keys):** document that unset `DEFAULT_RATE_LIMIT_PER_DAY` is unlimited (#2289), not a hidden 1000/day cap ([#11017](https://github.com/diegosouzapw/OmniRoute/issues/11017)) — thanks @RaviTharuma
- **fix:** strip unsupported message metadata for Groq ([#11026](https://github.com/diegosouzapw/OmniRoute/pull/11026)) — thanks @sanforex24h
- **fix(security):** close 4 STILL-REAL advisory findings (ACP RCE hardening, db-backups tier, uppercase authz bypass, spawn-veto drift) ([#11028](https://github.com/diegosouzapw/OmniRoute/pull/11028))
@@ -1168,7 +1169,6 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **cli:** guarantee non-empty [STARTUP] Fatal log on instrumentation-hook boot throw ([#10447](https://github.com/diegosouzapw/OmniRoute/pull/10447)) — thanks @adevwithpurpose
- **dashboard:** make provider card warning indicators expose the interaction they advertise ([#10448](https://github.com/diegosouzapw/OmniRoute/pull/10448)) — thanks @adevwithpurpose
- **dashboard:** media playground cards stop sending masked API key as Bearer ([#10449](https://github.com/diegosouzapw/OmniRoute/pull/10449)) — thanks @adevwithpurpose
- **sse:** mark gemini-3.5-flash as thinking-capable ([#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450)) — thanks @adevwithpurpose
- **dashboard:** send periodic WS heartbeat pings to stop live-dashboard reconnect churn ([#10452](https://github.com/diegosouzapw/OmniRoute/pull/10452)) — thanks @adevwithpurpose
- **sse:** do not ZWJ-obfuscate the substring hermes in user text ([#10488](https://github.com/diegosouzapw/OmniRoute/pull/10488)) — thanks @RaviTharuma
- **models:** correct Codex context and combo limit resolution ([#10533](https://github.com/diegosouzapw/OmniRoute/pull/10533)) — thanks @jackjinke
@@ -1230,6 +1230,11 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
- **fix(provider compatibility):** reject models-listing for Claude-Code-compatible connections before cached fallbacks can turn the unsupported request into an empty HTTP 200, and preserve raw no-auth model-override keys while resolving their sibling aliases so hidden-model and protocol overrides both survive ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952) — thanks @arminanton), re-derived from the closed ([#10795](https://github.com/diegosouzapw/OmniRoute/pull/10795) — thanks @rqzbeh) and reported in ([#7620](https://github.com/diegosouzapw/OmniRoute/issues/7620) — thanks @ahbeeahkao)
- **fix(codex-app-server):** default Codex-owned command/file execution to the `workspace-write` sandbox and deny its approval prompts unless the operator opts in; bind env-sourced capability tokens only to the matching env URL or an operator-local host; and stop the authenticated `/readyz` probe from following redirects ([#11281](https://github.com/diegosouzapw/OmniRoute/pull/11281)) — thanks @hartmark
- **fix(security):** refuse verbatim upstream-error passthrough when the body echoes a credential, redact relayed OCR and moderation errors, and cover the concrete `cookie`, `storageState` and `runtimeKey` call-log fields without hiding ordinary capability metadata ([#10952](https://github.com/diegosouzapw/OmniRoute/pull/10952)) — thanks @arminanton
- **fix(cli):** route MCP-backed CLI commands through the real Streamable HTTP JSON-RPC flow (`initialize``tools/call` with `Mcp-Session-Id`) instead of the nonexistent `/api/mcp/tools/call` route; decode tool results, honor the active remote context/auth/timeout, and align Combo, Skills, Compression and 1Proxy arguments with the server schemas ([#10960](https://github.com/diegosouzapw/OmniRoute/pull/10960) — thanks @YunyunZhai)
- **fix(providers):** remove retired Gemini 3.5 Flash entries from discovery, catalogs, aliases, rate limits, shared specs, docs and tests, superseding the pre-release thinking-capability workaround recorded for [#10286](https://github.com/diegosouzapw/OmniRoute/issues/10286) and [#10450](https://github.com/diegosouzapw/OmniRoute/pull/10450); the relevant commit was carried from open [#11259](https://github.com/diegosouzapw/OmniRoute/pull/11259) — thanks @backryun; direct-carry integration follow-up by @hartmark
- **fix(live-ws/dashboard):** accept the dev server's `http://0.0.0.0:20128` dashboard Origin without weakening the local-only default, stopping the `FORBIDDEN_ORIGIN` reconnect flood; render non-square provider and CLI logos at their intrinsic ratio so Next.js stops warning across the dashboard ([#11269](https://github.com/diegosouzapw/OmniRoute/pull/11269) — thanks @Minamaged18)
- **fix(ollama):** preserve every capability advertised by self-hosted Ollama models and defer chat selection to read time, so embedding and image routes accept eligible models without leaking endpoint-only models into provider wildcards or Auto-Combo; image retries remain restricted to the connections that advertised the selected model ([#11271](https://github.com/diegosouzapw/OmniRoute/pull/11271), corrected release-line port of [#11088](https://github.com/diegosouzapw/OmniRoute/pull/11088) for [#11087](https://github.com/diegosouzapw/OmniRoute/issues/11087) — thanks @yourspraveen)
- **fix(providers):** clamp out-of-vocabulary `reasoning_effort` values to the nearest tier declared by the exact provider/model, so `opencode-go/ox-alpha-free` maps the `medium` default to `high` while undeclared models remain pass-through ([#11274](https://github.com/diegosouzapw/OmniRoute/pull/11274) — thanks @linhdmn and @hartmark); builds on the learned accepted-set clamp from [#11232](https://github.com/diegosouzapw/OmniRoute/pull/11232) by @maxmad64bis
### 📝 Maintenance
@@ -1518,6 +1523,7 @@ _Living section — reconciled 2026-08-23 from all cycle commits (cycle open `ed
### 🙌 Contributors
Thanks to everyone whose work landed in v3.8.50:
@@ -1528,7 +1534,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@abhijeetnardele24-hash](https://github.com/abhijeetnardele24-hash) | #10498 |
| [@Abhishek4512009](https://github.com/Abhishek4512009) | #10494 |
| [@acc0mplish](https://github.com/acc0mplish) | #10732, #10948 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10450, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@adevwithpurpose](https://github.com/adevwithpurpose) | #9790, #10118, #10222, #10403, #10416, #10434, #10435, #10436, #10437, #10438, #10447, #10448, #10449, #10452, #10506, #10625, #10800, #10834, #10835, #10836, #10882, #10959 |
| [@AdityaMali16](https://github.com/AdityaMali16) | #11226 |
| [@adrianojiu](https://github.com/adrianojiu) | #8438 |
| [@agisota](https://github.com/agisota) | #9837 |
@@ -1556,7 +1562,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@AStupidBear](https://github.com/AStupidBear) | #10180 |
| [@azzaouiomar19-sketch](https://github.com/azzaouiomar19-sketch) | #10394 |
| [@b1nhm1nh](https://github.com/b1nhm1nh) | direct commit / report |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@backryun](https://github.com/backryun) | #8228, #8451, #8627, #8809, #8818, #9084, #9086, #9090, #9091, #9092, #9093, #9114, #9119, #9120, #9122, #9135, #9136, #9137, #9138, #9139, #9141, #9561, #9562, #9563, #9564, #9565, #9566, #9742, #9747, #9748, #9751, #9753, #9755, #9791, #9792, #9793, #9795, #9796, #9797, #9798, #9920, #9972, #9973, #9974, #9975, #9977, #9978, #9979, #9984, #9986, #9987, #9988, #9989, #9990, #9998, #10087, #10088, #10134, #10175, #10178, #10195, #10201, #10226, #10254, #10255, #10256, #10257, #10258, #10324, #10325, #10327, #10328, #10339, #10359, #10367, #10380, #10382, #10390, #10418, #10423, #10433, #10451, #10453, #10464, #10487, #10512, #10520, #10633, #10634, #10637, #10647, #10648, #10649, #10655, #10689, #10691, #10695, #10698, #10699, #10700, #10826, #10964, #11147, #11196, #11208, #11256, #11259, #11260, #11262, #11263, #11264, #11266, #11267, #11268 |
| [@Benson-mk](https://github.com/Benson-mk) | #8369 |
| [@benzntech](https://github.com/benzntech) | #9784, #9810, #9812, #9939, #10124, #10126, #10366, #10458 |
| [@Bl0ck154](https://github.com/Bl0ck154) | #9231 |
@@ -1619,7 +1625,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@Hsia97](https://github.com/Hsia97) | #10810 |
| [@hydraxman](https://github.com/hydraxman) | #10137, #10572 |
| [@Iammilansoni](https://github.com/Iammilansoni) | #9353, #9397 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228 |
| [@ignamiranda](https://github.com/ignamiranda) | #11195, #11204, #11206, #11215, #11224, #11227, #11228, #11282 |
| [@ikelvingo](https://github.com/ikelvingo) | #8591, #8872, #9053 |
| [@im-ecorp](https://github.com/im-ecorp) | #11244 |
| [@infinit-X](https://github.com/infinit-X) | #9095 |
@@ -1651,12 +1657,13 @@ Thanks to everyone whose work landed in v3.8.50:
| [@larin-vas](https://github.com/larin-vas) | #9828 |
| [@lazysaltyfish](https://github.com/lazysaltyfish) | direct commit / report |
| [@LeonG606](https://github.com/LeonG606) | #9457 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214 |
| [@linhdmn](https://github.com/linhdmn) | #10980, #11085, #11209, #11214, #11274 |
| [@Llliao1113](https://github.com/Llliao1113) | #8921 |
| [@lucasalx](https://github.com/lucasalx) | #9919 |
| [@lucasmellos](https://github.com/lucasmellos) | #8925 |
| [@lukiod](https://github.com/lukiod) | #8828 |
| [@luoyide](https://github.com/luoyide) | direct commit / report |
| [@maci0](https://github.com/maci0) | #11279 |
| [@mad-gooze](https://github.com/mad-gooze) | #9052 |
| [@mado90](https://github.com/mado90) | #11236 |
| [@maisdesign](https://github.com/maisdesign) | #8858 |
@@ -1669,6 +1676,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@MeRezaRezaei](https://github.com/MeRezaRezaei) | #10174, #10614, #10889, #10944, #11042, #11045 |
| [@Michael-Rocco-Goldmann](https://github.com/Michael-Rocco-Goldmann) | #9770, #9773, #9777, #9787 |
| [@MichaelYcJo](https://github.com/MichaelYcJo) | #8244, #10725, #10726 |
| [@Minamaged18](https://github.com/Minamaged18) | #11269 |
| [@minhlongs](https://github.com/minhlongs) | #10805 |
| [@minhnhat166](https://github.com/minhnhat166) | direct commit / report |
| [@MohitRawat017](https://github.com/MohitRawat017) | #8718, #8772, #9605 |
@@ -1697,7 +1705,7 @@ Thanks to everyone whose work landed in v3.8.50:
| [@PixmaNts](https://github.com/PixmaNts) | #9432 |
| [@pizzav-xyz](https://github.com/pizzav-xyz) | #9077 |
| [@Poid-ZA](https://github.com/Poid-ZA) | #9467, #10769 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031 |
| [@Prajeeth-12](https://github.com/Prajeeth-12) | #11031, #11265 |
| [@Prudhvivuda](https://github.com/Prudhvivuda) | #8807, #9014, #9015, #9016 |
| [@pucedoteth](https://github.com/pucedoteth) | #10607 |
| [@qianze0628](https://github.com/qianze0628) | #9038 |
@@ -1763,9 +1771,9 @@ Thanks to everyone whose work landed in v3.8.50:
| [@yansigit](https://github.com/yansigit) | #9834, #9909, #9911, #9917, #9921, #10065 |
| [@yawar-aquil](https://github.com/yawar-aquil) | #10668 |
| [@yidecode](https://github.com/yidecode) | #7223, #9212 |
| [@yourspraveen](https://github.com/yourspraveen) | #11165, #11176 |
| [@yourspraveen](https://github.com/yourspraveen) | #11087, #11088, #11165, #11176, #11271 |
| [@yulinlina](https://github.com/yulinlina) | #10013 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946 |
| [@YunyunZhai](https://github.com/YunyunZhai) | #10946, #10960 |
| [@yutuknown](https://github.com/yutuknown) | #8999 |
| [@zabrodschiipavel-sketch](https://github.com/zabrodschiipavel-sketch) | #9312 |
| [@zannen7](https://github.com/zannen7) | #10077 |

View File

@@ -375,11 +375,10 @@ export function sanitizeReasoningEffortForProvider(
? modelStr.slice(provider.length + 1)
: modelStr;
const declaredEfforts = getProviderModels(provider).find(
(entry) => entry.id === providerModelIdForClamp || entry.aliases?.includes(providerModelIdForClamp)
(entry) =>
entry.id === providerModelIdForClamp || entry.aliases?.includes(providerModelIdForClamp)
)?.supportedThinkingEfforts;
const declaredRanked = (
Array.isArray(declaredEfforts) ? declaredEfforts : []
)
const declaredRanked = (Array.isArray(declaredEfforts) ? declaredEfforts : [])
.map((tier) => ({ tier, rank: REASONING_EFFORT_ORDER.indexOf(tier) }))
.filter((x) => x.rank >= 0)
.sort((a, b) => a.rank - b.rank);

View File

@@ -1,6 +1,7 @@
import { z } from "zod";
import { skillRegistry } from "@/lib/skills/registry";
import { skillExecutor } from "@/lib/skills/executor";
import type { McpToolExtraLike } from "../scopeEnforcement.ts";
export const SkillListSchema = z.object({
apiKeyId: z.string().optional(),
@@ -9,17 +10,40 @@ export const SkillListSchema = z.object({
});
export const SkillEnableSchema = z.object({
apiKeyId: z.string(),
apiKeyId: z.string().optional(),
skillId: z.string(),
enabled: z.boolean(),
});
export const SkillExecuteSchema = z.object({
apiKeyId: z.string(),
skillName: z.string(),
input: z.record(z.string(), z.unknown()),
sessionId: z.string().optional(),
});
export const SkillExecuteSchema = z
.object({
apiKeyId: z.string().optional(),
skillId: z.string().optional(),
skillName: z.string().optional(),
input: z.record(z.string(), z.unknown()),
sessionId: z.string().optional(),
})
.refine((args) => Boolean(args.skillId || args.skillName), {
message: "skillId or skillName is required",
});
function authenticatedCallerId(extra: McpToolExtraLike | undefined): string | undefined {
const clientId = extra?.authInfo?.clientId;
return typeof clientId === "string" && clientId.trim() ? clientId.trim() : undefined;
}
async function resolveSkillTarget(
identifier: string,
requestedApiKeyId: string | undefined,
extra: McpToolExtraLike | undefined
) {
const callerId = authenticatedCallerId(extra);
const lookupOwnerId = callerId ?? requestedApiKeyId;
await skillRegistry.loadFromDatabase(lookupOwnerId);
const skill = skillRegistry.getSkill(identifier, lookupOwnerId);
if (!skill) throw new Error(`Skill not found: ${identifier}`);
return { skill, callerId, requestedApiKeyId };
}
export const skillTools = {
omniroute_skills_list: {
@@ -58,14 +82,20 @@ export const skillTools = {
description: "Enable or disable a specific skill by ID",
scopes: ["write:skills"],
inputSchema: SkillEnableSchema,
handler: async (args: z.infer<typeof SkillEnableSchema>) => {
await skillRegistry.loadFromDatabase(args.apiKeyId);
const skill = await skillRegistry.setEnabledById(args.skillId, args.apiKeyId, args.enabled);
if (!skill) {
handler: async (args: z.infer<typeof SkillEnableSchema>, extra?: McpToolExtraLike) => {
const target = await resolveSkillTarget(args.skillId, args.apiKeyId, extra);
const mutationOwnerId = target.callerId ?? target.requestedApiKeyId ?? target.skill.apiKeyId;
if (target.skill.apiKeyId !== mutationOwnerId) {
throw new Error(`Skill not found: ${args.skillId}`);
}
const skill = await skillRegistry.setEnabledById(
target.skill.id,
mutationOwnerId,
args.enabled
);
if (!skill) throw new Error(`Skill not found: ${args.skillId}`);
return { success: true, skillId: args.skillId, enabled: args.enabled };
return { success: true, skillId: target.skill.id, enabled: args.enabled };
},
},
@@ -74,9 +104,11 @@ export const skillTools = {
description: "Execute a skill with provided input and return the result",
scopes: ["execute:skills"],
inputSchema: SkillExecuteSchema,
handler: async (args: z.infer<typeof SkillExecuteSchema>) => {
const execution = await skillExecutor.execute(args.skillName, args.input, {
apiKeyId: args.apiKeyId,
handler: async (args: z.infer<typeof SkillExecuteSchema>, extra?: McpToolExtraLike) => {
const identifier = args.skillId ?? args.skillName!;
const target = await resolveSkillTarget(identifier, args.apiKeyId, extra);
const execution = await skillExecutor.execute(target.skill.name, args.input, {
apiKeyId: target.callerId ?? target.requestedApiKeyId ?? target.skill.apiKeyId,
sessionId: args.sessionId,
});

View File

@@ -11,6 +11,7 @@ import { toNumber } from "@/shared/utils/numeric";
import { isCompatibleProviderConnectionId } from "@/shared/utils/compatibleProviderId";
import { defaultLogger as log } from "@omniroute/open-sse/utils/logger";
import { getTokenLimit } from "../contextManager";
import { filterChatSelectableModels } from "../modelEndpointPolicy.ts";
import {
createModelCapabilityResolutionSnapshot,
getResolvedModelCapabilities,
@@ -542,10 +543,17 @@ export async function prepareVirtualAutoComboInputs(
// back to the static catalog only when the user has none. This keeps catalog-only
// models (e.g. openrouter/auto) out of every auto/* pool when the operator only
// synced a subset (e.g. OpenRouter with importFreeModelsOnly).
const [syncedByConnection, customModels] = await Promise.all([
const [syncedByConnectionRaw, customModelsRaw] = await Promise.all([
getSyncedAvailableModelsByConnection(providerId),
getCustomModels(providerId),
]);
const syncedByConnection = Object.fromEntries(
Object.entries(syncedByConnectionRaw).map(([connectionId, models]) => [
connectionId,
filterChatSelectableModels(providerId, models),
])
);
const customModels = filterChatSelectableModels(providerId, customModelsRaw);
const userVisibleIds = new Set<string>();
for (const models of Object.values(syncedByConnection)) {
for (const m of models) if (m.id && !hiddenModels?.has(m.id)) userVisibleIds.add(m.id);

View File

@@ -33,6 +33,7 @@ import { wildcardMatch } from "../wildcardRouter.ts";
import { getProviderModels } from "../../config/providerModels.ts";
import { getActiveSyncedCatalog } from "../../../src/lib/db/models/activeSyncedCatalog.ts";
import { filterAlibabaFreeTierModels, isAlibabaModelStudioProvider } from "../alibabaFreeTier.ts";
import { filterChatSelectableModels } from "../modelEndpointPolicy.ts";
import {
filterAlibabaFreeEligibleModels,
buildAlibabaFreeTierFilterContext,
@@ -144,10 +145,12 @@ async function collectProviderModelIds(providerId: string): Promise<string[]> {
const liveCatalog = await getActiveSyncedCatalog(providerId);
if (liveCatalog.authoritative) {
return liveCatalog.models.map((model) => model.id);
return filterChatSelectableModels(providerId, liveCatalog.models).map((model) => model.id);
}
return getProviderModels(providerId).map((model) => model.id);
return filterChatSelectableModels(providerId, getProviderModels(providerId)).map(
(model) => model.id
);
}
async function filterAlibabaFreeDrainedModelIds(

View File

@@ -1849,30 +1849,12 @@ export async function GET(
throw error;
}
// ponytail: Anthropic partner models via Model Garden publisher endpoint (Bearer only)
// ponytail: Anthropic partner models via Model Garden PublisherModels endpoint (Bearer only)
if (bearerToken) {
const psd = asRecord(connection.providerSpecificData);
const region =
(typeof psd.region === "string" && psd.region.trim()) || "us-central1";
// Extract project_id from SA JSON for project-scoped listing (mirrors executor URL pattern).
// Falls back to global publisher endpoint if no project available.
let anthropicModelsUrl: string;
let projectId: string | null = null;
if (credential) {
try {
const sa = JSON.parse(credential);
if (sa?.project_id) projectId = sa.project_id;
} catch { /* not SA JSON, skip */ }
}
if (projectId) {
anthropicModelsUrl = `https://aiplatform.googleapis.com/v1/projects/${projectId}/locations/${region}/publishers/anthropic/models`;
} else {
anthropicModelsUrl = `https://aiplatform.googleapis.com/v1/publishers/anthropic/models`;
}
try {
const anthropicResponse = await safeOutboundFetch(anthropicModelsUrl, {
const { parseVertexAnthropicModels, VERTEX_ANTHROPIC_PUBLISHER_MODELS_URL } =
await import("@/lib/providerModels/vertexAnthropicModelsParser");
const anthropicResponse = await safeOutboundFetch(VERTEX_ANTHROPIC_PUBLISHER_MODELS_URL, {
...SAFE_OUTBOUND_FETCH_PRESETS.modelsDiscovery,
guard: getProviderOutboundGuard(),
proxyConfig: proxy,
@@ -1884,14 +1866,10 @@ export async function GET(
});
if (anthropicResponse.ok) {
const anthropicData = await anthropicResponse.json();
const { parseVertexAnthropicModels } = await import(
"@/lib/providerModels/vertexAnthropicModelsParser"
);
allModels.push(...parseVertexAnthropicModels(anthropicData));
} else {
console.log("[models] Vertex Anthropic partner discovery failed", {
provider,
region,
status: anthropicResponse.status,
});
}

View File

@@ -127,16 +127,8 @@ async function postHandler(request, context) {
if (body.model && typeof body.model === "string" && !body.model.includes("/")) {
const combo = await getComboByName(body.model as string);
if (combo) {
const { executeImageCombo } = await import(
"@omniroute/open-sse/services/imageCombo"
);
return executeImageCombo(
body.model as string,
body,
{ request, policy },
startTime,
log
);
const { executeImageCombo } = await import("@omniroute/open-sse/services/imageCombo");
return executeImageCombo(body.model as string, body, { request, policy }, startTime, log);
}
}
@@ -155,6 +147,7 @@ async function postHandler(request, context) {
syncedEndpointRoute = await resolveLocalSyncedEndpointRoute(body.model, "images");
if (syncedEndpointRoute) {
provider = syncedEndpointRoute.provider;
requestedModel = syncedEndpointRoute.model;
body.model = `${syncedEndpointRoute.provider}/${syncedEndpointRoute.model}`;
isCustomModel = true;
}
@@ -246,7 +239,8 @@ async function postHandler(request, context) {
provider,
null,
syncedEndpointRoute?.connectionIds ?? null,
requestedModel );
requestedModel
);
if (!credentials) {
return errorResponse(
HTTP_STATUS.BAD_REQUEST,
@@ -279,6 +273,7 @@ async function postHandler(request, context) {
const execution = await executeImageWithCredentialFallback({
provider,
requestedModel,
allowedConnectionIds: syncedEndpointRoute?.connectionIds ?? null,
credentials,
execute: async (attemptCredentials) => {
let proxyInfo = null;
@@ -346,7 +341,10 @@ async function postHandler(request, context) {
});
}
const errorPayload = toJsonErrorPayload((result as any).error, "Image generation provider error") as {
const errorPayload = toJsonErrorPayload(
(result as any).error,
"Image generation provider error"
) as {
error?: { message?: string };
};
const message =

View File

@@ -7,6 +7,9 @@ interface VertexPublisherModel {
[key: string]: unknown;
}
export const VERTEX_ANTHROPIC_PUBLISHER_MODELS_URL =
"https://aiplatform.googleapis.com/v1beta1/publishers/anthropic/models";
export interface VertexAnthropicDiscoveryModel {
id: string;
name: string;
@@ -19,16 +22,21 @@ export interface VertexAnthropicDiscoveryModel {
export function parseVertexAnthropicModels(data: unknown): VertexAnthropicDiscoveryModel[] {
if (!data || typeof data !== "object") return [];
const envelope = data as { models?: unknown[] };
const models = Array.isArray(envelope.models) ? envelope.models : [];
const envelope = data as { publisherModels?: unknown };
const models = Array.isArray(envelope.publisherModels) ? envelope.publisherModels : [];
return models
.map((m: unknown) => {
if (!m || typeof m !== "object" || Array.isArray(m)) return null;
const model = m as VertexPublisherModel;
const rawName = typeof model.name === "string" ? model.name : "";
// "publishers/anthropic/models/claude-sonnet-4-6" or
// "projects/x/locations/y/publishers/anthropic/models/claude-sonnet-4-6"
const id = rawName.replace(/^(?:projects\/[^/]+\/locations\/[^/]+\/)?publishers\/anthropic\/models\//, "") || rawName;
const id =
rawName.replace(
/^(?:projects\/[^/]+\/locations\/[^/]+\/)?publishers\/anthropic\/models\//,
""
) || rawName;
if (!id) return null;
return {

View File

@@ -22,6 +22,7 @@ interface ImageGenerationResult {
interface ImageCredentialRetryOptions {
provider: string;
requestedModel: string | null;
allowedConnectionIds?: string[] | null;
credentials: any;
execute: (credentials: any) => Promise<ImageGenerationResult>;
// Injectable so unit tests can drive multi-account fallback deterministically
@@ -30,7 +31,8 @@ interface ImageCredentialRetryOptions {
selectNextCredentials?: (
provider: string,
requestedModel: string | null,
excludedConnectionIds: Set<string>
excludedConnectionIds: Set<string>,
allowedConnectionIds?: string[] | null
) => Promise<any>;
}
@@ -53,11 +55,18 @@ function isCredentialSentinel(credentials: any): boolean {
async function defaultSelectNextCredentials(
provider: string,
requestedModel: string | null,
excludedConnectionIds: Set<string>
excludedConnectionIds: Set<string>,
allowedConnectionIds?: string[] | null
) {
return getProviderCredentialsWithQuotaPreflight(provider, null, null, requestedModel, {
excludeConnectionIds: Array.from(excludedConnectionIds),
});
return getProviderCredentialsWithQuotaPreflight(
provider,
null,
allowedConnectionIds,
requestedModel,
{
excludeConnectionIds: Array.from(excludedConnectionIds),
}
);
}
/**
@@ -70,6 +79,7 @@ async function defaultSelectNextCredentials(
export async function executeImageWithCredentialFallback({
provider,
requestedModel,
allowedConnectionIds = null,
credentials,
execute,
selectNextCredentials = defaultSelectNextCredentials,
@@ -103,7 +113,8 @@ export async function executeImageWithCredentialFallback({
currentCredentials = await selectNextCredentials(
provider,
requestedModel,
excludedConnectionIds
excludedConnectionIds,
allowedConnectionIds
);
continue;
}
@@ -122,7 +133,8 @@ export async function executeImageWithCredentialFallback({
currentCredentials = await selectNextCredentials(
provider,
requestedModel,
excludedConnectionIds
excludedConnectionIds,
allowedConnectionIds
);
}

View File

@@ -24,8 +24,7 @@ test("combo suggest chama omniroute_best_combo_for_task via MCP", async () => {
});
const { mcpCallTool } = await import("../../bin/cli/mcpClient.mjs");
const result = await mcpCallTool("omniroute_best_combo_for_task", {
task: "Real-time code completions",
top: 5,
taskType: "coding",
});
globalThis.fetch = origFetch;
const candidates = (result as any).candidates;
@@ -44,35 +43,34 @@ test("combo suggest --max-cost/--max-latency-ms passa constraints", async () =>
}) as any;
const { mcpCallTool } = await import("../../bin/cli/mcpClient.mjs");
await mcpCallTool("omniroute_best_combo_for_task", {
task: "Summarize PDFs",
constraints: { maxCostUsd: 0.001, maxLatencyMs: 500 },
top: 3,
taskType: "analysis",
budgetConstraint: 0.001,
latencyConstraint: 500,
});
globalThis.fetch = origFetch;
const args = JSON.parse(captured.find((c) => /tools\/call/.test(String(c.init?.body || "")))?.init?.body || "{}")?.params?.arguments;
assert.equal(args.constraints.maxCostUsd, 0.001);
assert.equal(args.constraints.maxLatencyMs, 500);
assert.equal(args.top, 3);
const args = JSON.parse(
captured.find((c) => /tools\/call/.test(String(c.init?.body || "")))?.init?.body || "{}"
)?.params?.arguments;
assert.equal(args.taskType, "analysis");
assert.equal(args.budgetConstraint, 0.001);
assert.equal(args.latencyConstraint, 500);
});
test("combo suggest --weights passa pesos no body", async () => {
test("mcpCallTool reaplica a sessão e decodifica CallToolResult textual", async () => {
const origFetch = globalThis.fetch;
const captured: any[] = [];
globalThis.fetch = makeMcpStreamFetch({ toolResult: { candidates: [] } });
globalThis.fetch = makeMcpStreamFetch({ toolResult: { recommendedCombo: { name: "fast" } } });
const inner = globalThis.fetch;
globalThis.fetch = ((url: any, init: any) => {
captured.push({ url: String(url), init });
return inner(url, init);
}) as any;
const { mcpCallTool } = await import("../../bin/cli/mcpClient.mjs");
await mcpCallTool("omniroute_best_combo_for_task", {
task: "batch",
weights: { latency: 0.7, cost: 0.3 },
});
const result = await mcpCallTool("omniroute_best_combo_for_task", { taskType: "coding" });
globalThis.fetch = origFetch;
const args = JSON.parse(captured.find((c) => /tools\/call/.test(String(c.init?.body || "")))?.init?.body || "{}")?.params?.arguments;
assert.equal(args.weights.latency, 0.7);
assert.equal(args.weights.cost, 0.3);
const toolCall = captured.find((c) => /tools\/call/.test(String(c.init?.body || "")));
assert.equal(new Headers(toolCall?.init?.headers).get("mcp-session-id"), "sess-test");
assert.deepEqual(result, { recommendedCombo: { name: "fast" } });
});
test("combo suggest --switch chama /api/combos/switch com melhor combo", async () => {
@@ -83,16 +81,35 @@ test("combo suggest --switch chama /api/combos/switch com melhor combo", async (
if (String(url).includes("/api/mcp/stream")) {
const body = opts?.body ? JSON.parse(opts.body) : {};
if (body.method === "initialize") {
return Promise.resolve(makeMcpResp({ jsonrpc: "2.0", id: body.id, result: {} }, 200, { "mcp-session-id": "s" }));
return Promise.resolve(
makeMcpResp({ jsonrpc: "2.0", id: body.id, result: {} }, 200, { "mcp-session-id": "s" })
);
}
return Promise.resolve(makeMcpResp({ jsonrpc: "2.0", id: body.id, result: { candidates: [{ name: "best-combo", score: 0.95 }] } }));
assert.equal(new Headers(opts?.headers).get("mcp-session-id"), "s");
return Promise.resolve(
makeMcpResp({
jsonrpc: "2.0",
id: body.id,
result: {
content: [
{
type: "text",
text: JSON.stringify({ recommendedCombo: { name: "best-combo" } }),
},
],
},
})
);
}
return Promise.resolve(makeMcpResp({ switched: true }));
}) as any;
const { mcpCallTool } = await import("../../bin/cli/mcpClient.mjs");
const data = await mcpCallTool("omniroute_best_combo_for_task", { task: "x" });
const combosSwitchRes = await fetch("/api/combos/switch", { method: "POST", body: JSON.stringify({ name: (data as any).candidates[0].name }) });
const data = await mcpCallTool("omniroute_best_combo_for_task", { taskType: "coding" });
const combosSwitchRes = await fetch("/api/combos/switch", {
method: "POST",
body: JSON.stringify({ name: (data as any).recommendedCombo.name }),
});
assert.equal(combosSwitchRes.ok, true);
assert.ok(urls.some((u) => u.includes("/api/combos/switch")));
globalThis.fetch = origFetch;

View File

@@ -48,12 +48,14 @@ test("compression status chama omniroute_compression_status via mcp", async () =
await captureStdout(() => runCompressionStatus({}, makeCmd() as any));
globalThis.fetch = origFetch;
const body = JSON.parse(calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}");
const body = JSON.parse(
calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}"
);
assert.equal(body.method, "tools/call");
assert.equal(body.params.name, "omniroute_compression_status");
});
test("compression configure envia configuração via mcp", async () => {
test("compression configure envia apenas campos aceitos pelo schema MCP", async () => {
const calls: unknown[] = [];
const origFetch = globalThis.fetch;
globalThis.fetch = makeMcpStreamFetch({ toolResult: { success: true } });
@@ -65,16 +67,53 @@ test("compression configure envia configuração via mcp", async () => {
const { runCompressionConfigure } = await import("../../bin/cli/commands/compression.mjs");
await captureStdout(() =>
runCompressionConfigure({ engine: "caveman", cavemanAggressiveness: 0.8 }, makeCmd() as any)
runCompressionConfigure(
{
engine: "standard",
autoTriggerMode: "aggressive",
maxTokens: 4096,
targetRatio: 0.45,
preserveSystemPrompt: true,
},
makeCmd() as any
)
);
globalThis.fetch = origFetch;
const body = JSON.parse(calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}");
const body = JSON.parse(
calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}"
);
assert.equal(body.method, "tools/call");
assert.equal(body.params.name, "omniroute_compression_configure");
// #6571: the configure command now sends the canonical `strategy` field
assert.equal(body.params.arguments.strategy, "caveman");
assert.ok(body.params.arguments.caveman?.aggressiveness === 0.8);
assert.deepEqual(body.params.arguments, {
strategy: "standard",
autoTriggerMode: "aggressive",
maxTokens: 4096,
targetRatio: 0.45,
preserveSystemPrompt: true,
});
assert.equal("caveman" in body.params.arguments, false);
assert.equal("rtk" in body.params.arguments, false);
assert.equal("languagePack" in body.params.arguments, false);
});
test("compression combo stats maps --period to the canonical since field", async () => {
const calls: any[] = [];
const origFetch = globalThis.fetch;
const streamFetch = makeMcpStreamFetch({ toolResult: { requests: 3 } });
globalThis.fetch = (async (url: string, init?: any) => {
calls.push({ url: String(url), init });
return streamFetch(url, init);
}) as any;
const { runCompressionComboStats } = await import("../../bin/cli/commands/compression.mjs");
await captureStdout(() => runCompressionComboStats({ period: "30d" }, makeCmd() as any));
globalThis.fetch = origFetch;
const body = JSON.parse(
calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}"
);
assert.deepEqual(body.params.arguments, { since: "30d" });
});
test("compression engine set chama omniroute_set_compression_engine", async () => {
@@ -93,7 +132,9 @@ test("compression engine set chama omniroute_set_compression_engine", async () =
});
globalThis.fetch = origFetch;
const body = JSON.parse(calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}");
const body = JSON.parse(
calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}"
);
assert.equal(body.method, "tools/call");
assert.equal(body.params.name, "omniroute_set_compression_engine");
assert.equal(body.params.arguments.engine, "rtk");
@@ -135,7 +176,9 @@ test("compression engine set normaliza hybrid → stacked alias", async () => {
});
globalThis.fetch = origFetch;
const body = JSON.parse(calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}");
const body = JSON.parse(
calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}"
);
assert.equal(body.params.arguments.engine, "stacked");
});
@@ -208,7 +251,9 @@ test("compression status falls back to /api/settings/compression on MCP 404", as
if (url.includes("/api/mcp/stream")) {
const body = opts?.body ? JSON.parse(opts.body) : {};
if (body.method === "initialize") {
return Promise.resolve(makeMcpResp({ jsonrpc: "2.0", id: body.id, result: {} }, 200, { "mcp-session-id": "s" }));
return Promise.resolve(
makeMcpResp({ jsonrpc: "2.0", id: body.id, result: {} }, 200, { "mcp-session-id": "s" })
);
}
return Promise.resolve(makeMcpResp({ error: "not mounted" }, 404));
}
@@ -230,9 +275,18 @@ test("compression status falls back to /api/settings/compression on MCP 404", as
globalThis.fetch = origFetch;
const first = callOrder[0] ?? "";
assert.ok(first.includes("/api/mcp/stream"), "should attempt MCP first");
assert.ok(callOrder.some((u) => u.includes("/api/settings/compression")), "should fall back to REST");
assert.ok(callOrder.some((u) => u.includes("/api/context/combos")), "should fetch combos");
assert.ok(callOrder.some((u) => u.includes("/api/context/analytics")), "should fetch analytics");
assert.ok(
callOrder.some((u) => u.includes("/api/settings/compression")),
"should fall back to REST"
);
assert.ok(
callOrder.some((u) => u.includes("/api/context/combos")),
"should fetch combos"
);
assert.ok(
callOrder.some((u) => u.includes("/api/context/analytics")),
"should fetch analytics"
);
});
test("compression engine set falls back to PUT /api/settings/compression on MCP 404", async () => {
@@ -247,7 +301,9 @@ test("compression engine set falls back to PUT /api/settings/compression on MCP
if (url.includes("/api/mcp/stream")) {
const body = opts?.body ? JSON.parse(opts.body) : {};
if (body.method === "initialize") {
return Promise.resolve(makeMcpResp({ jsonrpc: "2.0", id: body.id, result: {} }, 200, { "mcp-session-id": "s" }));
return Promise.resolve(
makeMcpResp({ jsonrpc: "2.0", id: body.id, result: {} }, 200, { "mcp-session-id": "s" })
);
}
return Promise.resolve(makeMcpResp({ error: "not mounted" }, 404));
}

View File

@@ -1,5 +1,38 @@
import test from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
const originalDataDir = process.env.DATA_DIR;
const originalKeychainDisabled = process.env.OMNIROUTE_CONTEXT_KEYCHAIN_DISABLED;
const testDataDir = mkdtempSync(join(tmpdir(), "omniroute-cli-mcp-call-"));
process.env.DATA_DIR = testDataDir;
process.env.OMNIROUTE_CONTEXT_KEYCHAIN_DISABLED = "1";
writeFileSync(
join(testDataDir, "config.json"),
JSON.stringify({
version: 1,
currentContext: "remote-test",
contexts: {
"remote-test": {
baseUrl: "https://remote.example.test",
accessToken: "remote-context-token",
},
},
})
);
test.after(() => {
if (originalDataDir === undefined) delete process.env.DATA_DIR;
else process.env.DATA_DIR = originalDataDir;
if (originalKeychainDisabled === undefined) {
delete process.env.OMNIROUTE_CONTEXT_KEYCHAIN_DISABLED;
} else {
process.env.OMNIROUTE_CONTEXT_KEYCHAIN_DISABLED = originalKeychainDisabled;
}
rmSync(testDataDir, { recursive: true, force: true });
});
// ---- helpers ----
@@ -32,16 +65,12 @@ async function captureStdout(fn: () => Promise<void>): Promise<string> {
return chunks.join("");
}
function makeCmd(output = "json") {
return { optsWithGlobals: () => ({ output, quiet: output !== "table" }) };
}
// Simulate a /api/mcp/stream endpoint that speaks JSON-RPC 2.0
function makeMcpStreamFetch(
toolResult: { content: { type: string; text: string }[] } = {
content: [{ type: "text", text: "hello" }],
},
callStatus = 200,
callStatus = 200
) {
return ((url: string, opts: unknown) => {
const u = String(url);
@@ -57,19 +86,14 @@ function makeMcpStreamFetch(
makeResp(
{ jsonrpc: "2.0", id: 1, result: { protocolVersion: "2024-11-05", capabilities: {} } },
200,
{ "mcp-session-id": "test-session-123" },
),
{ "mcp-session-id": "test-session-123" }
)
);
}
// tools/call
if (body && body.method === "tools/call") {
return Promise.resolve(
makeResp(
{ jsonrpc: "2.0", id: 2, result: toolResult },
callStatus,
),
);
return Promise.resolve(makeResp({ jsonrpc: "2.0", id: 2, result: toolResult }, callStatus));
}
return Promise.resolve(makeResp({ error: "unknown method" }, 400));
@@ -78,11 +102,172 @@ function makeMcpStreamFetch(
// ---- tests ----
test("mcp call uses the active remote context and decodes structured tool output", async () => {
const calls: Array<{ url: string; headers: Headers }> = [];
const origFetch = globalThis.fetch;
globalThis.fetch = (async (url: string, opts: { body?: string; headers?: HeadersInit }) => {
const body = opts.body ? JSON.parse(opts.body) : null;
calls.push({ url: String(url), headers: new Headers(opts.headers) });
if (body?.method === "initialize") {
return makeResp({ jsonrpc: "2.0", id: 1, result: { protocolVersion: "2024-11-05" } }, 200, {
"mcp-session-id": "remote-session",
});
}
return makeResp({
jsonrpc: "2.0",
id: 2,
result: {
structuredContent: { status: "healthy", source: "remote-context" },
content: [{ type: "text", text: "fallback content must not win" }],
},
});
}) as any;
try {
const output = await captureStdout(async () => {
const { runMcpCallCommand } = await import("../../bin/cli/commands/mcp.mjs");
const exitCode = await runMcpCallCommand("omniroute_get_health", {}, { stream: false });
assert.equal(exitCode, 0);
});
assert.equal(calls.length, 2);
assert.ok(calls.every((call) => call.url === "https://remote.example.test/api/mcp/stream"));
assert.ok(
calls.every((call) => call.headers.get("authorization") === "Bearer remote-context-token")
);
assert.deepEqual(JSON.parse(output), { status: "healthy", source: "remote-context" });
} finally {
globalThis.fetch = origFetch;
}
});
test("mcp call lets explicit base URL and API key override the active context", async () => {
const calls: Array<{ url: string; headers: Headers }> = [];
const origFetch = globalThis.fetch;
globalThis.fetch = (async (url: string, opts: { body?: string; headers?: HeadersInit }) => {
const body = opts.body ? JSON.parse(opts.body) : null;
calls.push({ url: String(url), headers: new Headers(opts.headers) });
if (body?.method === "initialize") {
return makeResp({ jsonrpc: "2.0", id: 1, result: {} }, 200, {
"mcp-session-id": "explicit-session",
});
}
return makeResp({
jsonrpc: "2.0",
id: 2,
result: { content: [{ type: "text", text: "ok" }] },
});
}) as any;
try {
const { runMcpCallCommand } = await import("../../bin/cli/commands/mcp.mjs");
const exitCode = await runMcpCallCommand(
"test_tool",
{},
{ stream: false },
{
baseUrl: "https://explicit.example.test",
apiKey: "explicit-api-key",
output: "json",
}
);
assert.equal(exitCode, 0);
assert.equal(calls.length, 2);
assert.ok(calls.every((call) => call.url === "https://explicit.example.test/api/mcp/stream"));
assert.ok(
calls.every((call) => call.headers.get("authorization") === "Bearer explicit-api-key")
);
} finally {
globalThis.fetch = origFetch;
}
});
test("mcp call retries a transient MCP initialization failure", async () => {
let initializeAttempts = 0;
let toolCalls = 0;
const origFetch = globalThis.fetch;
globalThis.fetch = (async (_url: string, opts: { body?: string }) => {
const body = opts.body ? JSON.parse(opts.body) : null;
if (body?.method === "initialize") {
initializeAttempts++;
if (initializeAttempts === 1) {
return makeResp({ error: "temporarily unavailable" }, 503, { "retry-after": "0" });
}
return makeResp({ jsonrpc: "2.0", id: 1, result: {} }, 200, {
"mcp-session-id": "retry-session",
});
}
toolCalls++;
return makeResp({
jsonrpc: "2.0",
id: 2,
result: { content: [{ type: "text", text: "ok" }] },
});
}) as any;
try {
await captureStdout(async () => {
const { runMcpCallCommand } = await import("../../bin/cli/commands/mcp.mjs");
const exitCode = await runMcpCallCommand(
"test_tool",
{},
{ stream: false },
{ baseUrl: "https://retry.example.test", retryMax: 2 }
);
assert.equal(exitCode, 0);
});
assert.equal(initializeAttempts, 2);
assert.equal(toolCalls, 1);
} finally {
globalThis.fetch = origFetch;
}
});
test("mcp call enforces the CLI timeout and returns the timeout exit code", async () => {
let receivedAbortSignal = false;
const origFetch = globalThis.fetch;
globalThis.fetch = ((_url: string, opts: { signal?: AbortSignal }) =>
new Promise((_resolve, reject) => {
const fallback = setTimeout(() => reject(new Error("missing fetch timeout")), 100);
const abort = () => {
clearTimeout(fallback);
const error = new Error("request aborted");
error.name = "AbortError";
reject(error);
};
receivedAbortSignal = opts.signal instanceof AbortSignal;
if (opts.signal?.aborted) abort();
else opts.signal?.addEventListener("abort", abort, { once: true });
})) as any;
try {
const { runMcpCallCommand } = await import("../../bin/cli/commands/mcp.mjs");
const exitCode = await runMcpCallCommand(
"test_tool",
{},
{ stream: false },
{
baseUrl: "https://timeout.example.test",
timeout: 10,
retry: false,
}
);
assert.equal(receivedAbortSignal, true);
assert.equal(exitCode, 124);
} finally {
globalThis.fetch = origFetch;
}
});
test("mcp call sends JSON-RPC initialize then tools/call", async () => {
const calls: Array<{ url: string; body: unknown }> = [];
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: unknown) => {
const u = String(url);
globalThis.fetch = ((_url: string, opts: unknown) => {
const u = String(_url);
const body = opts?.body ? JSON.parse(opts.body) : null;
calls.push({ url: u, body });
@@ -91,8 +276,8 @@ test("mcp call sends JSON-RPC initialize then tools/call", async () => {
makeResp(
{ jsonrpc: "2.0", id: 1, result: { protocolVersion: "2024-11-05", capabilities: {} } },
200,
{ "mcp-session-id": "sess-1" },
),
{ "mcp-session-id": "sess-1" }
)
);
}
if (body && body.method === "tools/call") {
@@ -101,21 +286,19 @@ test("mcp call sends JSON-RPC initialize then tools/call", async () => {
jsonrpc: "2.0",
id: 2,
result: { content: [{ type: "text", text: "ok" }] },
}),
})
);
}
return Promise.resolve(makeResp({ error: "unknown" }, 400));
}) as any;
try {
const { runMcpCallCommand } = await import(
"../../bin/cli/commands/mcp.mjs"
);
const { runMcpCallCommand } = await import("../../bin/cli/commands/mcp.mjs");
const exitCode = await runMcpCallCommand(
"omniroute_get_health",
{},
{ stream: false },
{ baseUrl: "http://localhost:20128" },
{ baseUrl: "http://localhost:20128" }
);
assert.equal(exitCode, 0);
@@ -130,44 +313,42 @@ test("mcp call sends JSON-RPC initialize then tools/call", async () => {
});
test("mcp call passes session-id header on tools/call", async () => {
let callHeaders: Record<string, string> = {};
let callHeaders = new Headers();
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: unknown) => {
globalThis.fetch = ((_url: string, opts: unknown) => {
const body = opts?.body ? JSON.parse(opts.body) : null;
if (body && body.method === "initialize") {
return Promise.resolve(
makeResp(
{ jsonrpc: "2.0", id: 1, result: { protocolVersion: "2024-11-05", capabilities: {} } },
200,
{ "mcp-session-id": "sess-abc" },
),
{ "mcp-session-id": "sess-abc" }
)
);
}
if (body && body.method === "tools/call") {
callHeaders = opts.headers || {};
callHeaders = new Headers(opts.headers);
return Promise.resolve(
makeResp({
jsonrpc: "2.0",
id: 2,
result: { content: [{ type: "text", text: "ok" }] },
}),
})
);
}
return Promise.resolve(makeResp({ error: "unknown" }, 400));
}) as any;
try {
const { runMcpCallCommand } = await import(
"../../bin/cli/commands/mcp.mjs"
);
const { runMcpCallCommand } = await import("../../bin/cli/commands/mcp.mjs");
const exitCode = await runMcpCallCommand(
"test_tool",
{ key: "val" },
{ stream: false },
{ baseUrl: "http://localhost:20128" },
{ baseUrl: "http://localhost:20128" }
);
assert.equal(exitCode, 0);
assert.equal(callHeaders["mcp-session-id"], "sess-abc");
assert.equal(callHeaders.get("mcp-session-id"), "sess-abc");
} finally {
globalThis.fetch = origFetch;
}
@@ -180,15 +361,8 @@ test("mcp call prints result content to stdout", async () => {
});
const output = await captureStdout(async () => {
const { runMcpCallCommand } = await import(
"../../bin/cli/commands/mcp.mjs"
);
await runMcpCallCommand(
"test",
{},
{ stream: false },
{ baseUrl: "http://localhost:20128" },
);
const { runMcpCallCommand } = await import("../../bin/cli/commands/mcp.mjs");
await runMcpCallCommand("test", {}, { stream: false }, { baseUrl: "http://localhost:20128" });
});
globalThis.fetch = origFetch;
@@ -197,15 +371,15 @@ test("mcp call prints result content to stdout", async () => {
test("mcp call prints error on non-ok response", async () => {
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: unknown) => {
globalThis.fetch = ((_url: string, opts: unknown) => {
const body = opts?.body ? JSON.parse(opts.body) : null;
if (body && body.method === "initialize") {
return Promise.resolve(
makeResp(
{ jsonrpc: "2.0", id: 1, result: { protocolVersion: "2024-11-05", capabilities: {} } },
200,
{ "mcp-session-id": "sess-1" },
),
{ "mcp-session-id": "sess-1" }
)
);
}
if (body && body.method === "tools/call") {
@@ -215,14 +389,12 @@ test("mcp call prints error on non-ok response", async () => {
}) as any;
try {
const { runMcpCallCommand } = await import(
"../../bin/cli/commands/mcp.mjs"
);
const { runMcpCallCommand } = await import("../../bin/cli/commands/mcp.mjs");
const exitCode = await runMcpCallCommand(
"bad_tool",
{},
{ stream: false },
{ baseUrl: "http://localhost:20128" },
{ baseUrl: "http://localhost:20128" }
);
assert.equal(exitCode, 1);
} finally {
@@ -232,15 +404,15 @@ test("mcp call prints error on non-ok response", async () => {
test("mcp call with stream reads SSE data", async () => {
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: unknown) => {
globalThis.fetch = ((_url: string, opts: unknown) => {
const body = opts?.body ? JSON.parse(opts.body) : null;
if (body && body.method === "initialize") {
return Promise.resolve(
makeResp(
{ jsonrpc: "2.0", id: 1, result: { protocolVersion: "2024-11-05", capabilities: {} } },
200,
{ "mcp-session-id": "sess-stream" },
),
{ "mcp-session-id": "sess-stream" }
)
);
}
if (body && body.method === "tools/call") {
@@ -265,15 +437,8 @@ test("mcp call with stream reads SSE data", async () => {
}) as any;
const output = await captureStdout(async () => {
const { runMcpCallCommand } = await import(
"../../bin/cli/commands/mcp.mjs"
);
await runMcpCallCommand(
"test",
{},
{ stream: true },
{ baseUrl: "http://localhost:20128" },
);
const { runMcpCallCommand } = await import("../../bin/cli/commands/mcp.mjs");
await runMcpCallCommand("test", {}, { stream: true }, { baseUrl: "http://localhost:20128" });
});
globalThis.fetch = origFetch;
@@ -283,7 +448,7 @@ test("mcp call with stream reads SSE data", async () => {
test("mcp status reads online field", async () => {
const origFetch = globalThis.fetch;
globalThis.fetch = (async (_url: string | URL, init?: unknown) => {
globalThis.fetch = (async (_url: string | URL, _init?: unknown) => {
const u = String(_url);
if (u.includes("/api/health")) {
return makeResp({ status: "ok" }) as any;
@@ -301,9 +466,7 @@ test("mcp status reads online field", async () => {
}) as any;
const output = await captureStdout(async () => {
const { runMcpStatusCommand } = await import(
"../../bin/cli/commands/mcp.mjs"
);
const { runMcpStatusCommand } = await import("../../bin/cli/commands/mcp.mjs");
const exitCode = await runMcpStatusCommand({});
assert.equal(exitCode, 0);
});
@@ -328,16 +491,14 @@ test("mcp status json mode prints full object", async () => {
transport: "stdio",
enabled: true,
toolsCount: 107,
}),
})
);
}
return Promise.resolve(makeResp({ error: "not found" }, 404));
}) as any;
const output = await captureStdout(async () => {
const { runMcpStatusCommand } = await import(
"../../bin/cli/commands/mcp.mjs"
);
const { runMcpStatusCommand } = await import("../../bin/cli/commands/mcp.mjs");
const exitCode = await runMcpStatusCommand({ json: true });
assert.equal(exitCode, 0);
});

View File

@@ -25,33 +25,57 @@ test("oneproxy status chama omniroute_oneproxy_stats via MCP", async () => {
assert.ok(calls.length >= 0);
});
test("oneproxy stats passa provider e period para MCP", async () => {
test("oneproxy stats envia o objeto vazio exigido pelo schema MCP", async () => {
const calls: any[] = [];
const origFetch = globalThis.fetch;
globalThis.fetch = makeMcpStreamFetch({ toolResult: { requests: 5000 } });
const { mcpCallTool } = await import("../../bin/cli/mcpClient.mjs");
const result = await mcpCallTool("omniroute_oneproxy_stats", { provider: "openai", period: "24h" });
const streamFetch = makeMcpStreamFetch({ toolResult: { stats: {}, status: {} } });
globalThis.fetch = (async (url: string, init?: any) => {
calls.push({ url: String(url), init });
return streamFetch(url, init);
}) as any;
const { runOneproxyStats } = await import("../../bin/cli/commands/oneproxy.mjs");
await runOneproxyStats({}, makeCmd() as any);
globalThis.fetch = origFetch;
assert.deepEqual(result, { requests: 5000 });
const body = JSON.parse(
calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}"
);
assert.deepEqual(body.params.arguments, {});
});
test("oneproxy fetch chama omniroute_oneproxy_fetch com count e type", async () => {
test("oneproxy fetch maps count/type to limit/protocol and emits items", async () => {
const calls: any[] = [];
const origFetch = globalThis.fetch;
globalThis.fetch = makeMcpStreamFetch({ toolResult: { proxies: [{ host: "10.0.0.1", type: "http" }] } });
const { mcpCallTool } = await import("../../bin/cli/mcpClient.mjs");
const result = await mcpCallTool("omniroute_oneproxy_fetch", { count: 5, type: "http" });
const streamFetch = makeMcpStreamFetch({
toolResult: { items: [{ host: "10.0.0.1", type: "http" }], total: 1 },
});
globalThis.fetch = (async (url: string, init?: any) => {
calls.push({ url: String(url), init });
return streamFetch(url, init);
}) as any;
const { runOneproxyFetch } = await import("../../bin/cli/commands/oneproxy.mjs");
await runOneproxyFetch({ count: 5, type: "http" }, makeCmd() as any);
globalThis.fetch = origFetch;
assert.equal((result as any).proxies[0].host, "10.0.0.1");
assert.equal((result as any).proxies[0].type, "http");
const body = JSON.parse(
calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}"
);
assert.deepEqual(body.params.arguments, { limit: 5, protocol: "http" });
});
test("oneproxy rotate chama omniroute_oneproxy_rotate com provider", async () => {
test("oneproxy rotate envia somente a strategy aceita pelo schema MCP", async () => {
const calls: any[] = [];
const origFetch = globalThis.fetch;
globalThis.fetch = makeMcpStreamFetch({ toolResult: { rotated: true, newProxy: "10.0.0.2" } });
const { mcpCallTool } = await import("../../bin/cli/mcpClient.mjs");
const result = await mcpCallTool("omniroute_oneproxy_rotate", { provider: "anthropic" });
const streamFetch = makeMcpStreamFetch({ toolResult: { host: "10.0.0.2", type: "http" } });
globalThis.fetch = (async (url: string, init?: any) => {
calls.push({ url: String(url), init });
return streamFetch(url, init);
}) as any;
const { runOneproxyRotate } = await import("../../bin/cli/commands/oneproxy.mjs");
await runOneproxyRotate({ strategy: "quality" }, makeCmd() as any);
globalThis.fetch = origFetch;
assert.equal((result as any).rotated, true);
assert.equal((result as any).newProxy, "10.0.0.2");
const body = JSON.parse(
calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}"
);
assert.deepEqual(body.params.arguments, { strategy: "quality" });
});
test("oneproxy config set envia PUT /api/settings/oneproxy", async () => {

View File

@@ -118,7 +118,10 @@ test("resilience profile set usa JSON-RPC tools/call", async () => {
globalThis.fetch = makeMcpStreamFetch({ toolResult: {} });
const inner = globalThis.fetch;
globalThis.fetch = ((url: any, init: any) => {
if (String(url).includes("/api/mcp/stream") && String(init?.body || "").includes("tools/call")) {
if (
String(url).includes("/api/mcp/stream") &&
String(init?.body || "").includes("tools/call")
) {
capturedCall = JSON.parse(init.body);
}
return inner(url, init);

View File

@@ -1,6 +1,10 @@
import test from "node:test";
import { makeMcpResp, makeMcpStreamFetch } from "./helpers/mcpStreamMock.ts";
import assert from "node:assert/strict";
import {
SkillEnableSchema,
SkillExecuteSchema,
} from "../../open-sse/mcp-server/tools/skillTools.ts";
const SKILLS_DATA = [
{ id: "sk_pdf", name: "PDF Parser", type: "sandbox", version: "1.0.0", enabled: true },
@@ -130,7 +134,9 @@ test("runSkillsEnable usa JSON-RPC tools/call", async () => {
globalThis.fetch = origFetch;
assert.ok(calls.some((x) => String(x.url).includes("/api/mcp/stream")));
const callBody = JSON.parse(calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}");
const callBody = JSON.parse(
calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}"
);
assert.equal(callBody.method, "tools/call");
assert.equal(callBody.params.name, "omniroute_skills_enable");
assert.equal(callBody.params.arguments.skillId, "sk_pdf");
@@ -138,6 +144,17 @@ test("runSkillsEnable usa JSON-RPC tools/call", async () => {
assert.ok(out.includes("sk_pdf"));
});
test("skill MCP schemas accept the CLI's id-based payloads", () => {
assert.deepEqual(SkillEnableSchema.parse({ skillId: "sk_pdf", enabled: true }), {
skillId: "sk_pdf",
enabled: true,
});
assert.deepEqual(SkillExecuteSchema.parse({ skillId: "sk_pdf", input: { file: "doc.pdf" } }), {
skillId: "sk_pdf",
input: { file: "doc.pdf" },
});
});
test("runSkillsExecute usa JSON-RPC tools/call", async () => {
const calls: unknown[] = [];
const origFetch = globalThis.fetch;
@@ -154,7 +171,9 @@ test("runSkillsExecute usa JSON-RPC tools/call", async () => {
);
globalThis.fetch = origFetch;
const callBody = JSON.parse(calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}");
const callBody = JSON.parse(
calls.find((x) => String(x.init?.body || "").includes("tools/call"))?.init?.body || "{}"
);
assert.equal(callBody.method, "tools/call");
assert.equal(callBody.params.name, "omniroute_skills_execute");
assert.equal(callBody.params.arguments.skillId, "sk_pdf");

View File

@@ -98,7 +98,9 @@ test("expandAutoComboCandidatePool excludes catalog-only models (openrouter/auto
);
assert.ok(
expanded.some((t) => t.provider === "openrouter" && t.modelStr === "openrouter/liquid/lfm-2.5-2.6b:free"),
expanded.some(
(t) => t.provider === "openrouter" && t.modelStr === "openrouter/liquid/lfm-2.5-2.6b:free"
),
"a synced free model must be expanded into the pool"
);
});
@@ -171,3 +173,52 @@ test("virtual auto-combo pool filters EVERY provider with partial sync, not just
"kilocode pool must contain exactly the two synced models"
);
});
test("virtual auto-combo pool keeps only chat-selectable models from an Ollama connection", async () => {
const connection = await providersDb.createProviderConnection({
provider: "ollama-local",
authType: "apikey",
name: "Self-hosted Ollama",
apiKey: "test-key",
providerSpecificData: { baseUrl: "http://127.0.0.1:11434/v1" },
});
const connectionId = (connection as { id?: string }).id;
assert.ok(connectionId, "created Ollama connection must expose an id");
await modelsDb.replaceSyncedAvailableModelsForConnection("ollama-local", connectionId, [
{
id: "image-model",
name: "Image Model",
apiFormat: "images-generations",
supportedEndpoints: ["images"],
},
{
id: "embedding-model",
name: "Embedding Model",
apiFormat: "embeddings",
supportedEndpoints: ["embeddings"],
},
{
id: "chat-model",
name: "Chat Model",
apiFormat: "chat-completions",
supportedEndpoints: ["chat"],
},
]);
const prepared = await virtualFactory.prepareVirtualAutoComboInputs();
const ollamaCandidates = prepared.regularCandidates.filter(
(candidate) => candidate.provider === "ollama-local"
);
assert.deepEqual(
ollamaCandidates.map((candidate) => candidate.model),
["chat-model"],
"image- and embedding-only models must not enter a chat auto-combo pool"
);
assert.deepEqual(
ollamaCandidates[0]?.allowedConnectionIds,
[connectionId],
"the surviving chat model must remain scoped to its advertising connection"
);
});

View File

@@ -398,6 +398,25 @@ test("#8926: active synced catalog replaces static wildcard entries", async () =
);
});
test("Ollama provider wildcards exclude endpoint-only image and embedding models", async () => {
const connectionId = `ollama-capability-wildcard-${Date.now()}`;
await seedSyncedModels("ollama-local", connectionId, []);
await replaceSyncedAvailableModelsForConnection("ollama-local", connectionId, [
{ id: "chat-model", name: "Chat", supportedEndpoints: ["chat"] },
{ id: "image-model", name: "Image", supportedEndpoints: ["images"] },
{ id: "embedding-model", name: "Embedding", supportedEndpoints: ["embeddings"] },
]);
const result = await expandProviderWildcardsInCombo(
makeCombo(["ollama-local/*"], "ollama-chat-only")
);
assert.deepEqual(
result.models.map((entry) => (entry as { model: string }).model),
["ollama-local/chat-model"]
);
});
test("#8926: inactive synced catalog does not override static wildcard fallback", async () => {
const providerId = "openai";
const inactiveModelId = "inactive-only-model-8926";

View File

@@ -523,7 +523,8 @@ describe("Conol web provider", () => {
// Configuration must complete before the turn is submitted.
const turnIndex = calls.findIndex(
(call) => call.url.endsWith("/api/sessions/session_123/messages") && call.init?.method === "POST"
(call) =>
call.url.endsWith("/api/sessions/session_123/messages") && call.init?.method === "POST"
);
const lastModelIndex = calls.map((call) => call.url.endsWith("/model")).lastIndexOf(true);
assert.ok(lastModelIndex < turnIndex, "model config must precede the message turn");

View File

@@ -75,10 +75,10 @@ test("disabled scheduler emits [STARTUP] Credential health scheduler disabled vi
});
test("instrumentation-node.ts wires initCredentialHealthCheck return to the log conditional", () => {
const src = readFileSync(
resolve(projectRoot, "src/instrumentation-node.ts"),
"utf8"
).replace(/\r\n/g, "\n");
const src = readFileSync(resolve(projectRoot, "src/instrumentation-node.ts"), "utf8").replace(
/\r\n/g,
"\n"
);
assert.match(
src,

View File

@@ -7,9 +7,7 @@ const mod = await import("../../open-sse/executors/promptql.ts");
const usage = await import("../../open-sse/services/usage/promptql.ts");
const models = await import("../../open-sse/services/promptqlModels.ts");
const { getModelsByProviderId } = await import("../../open-sse/config/providerModels.ts");
const { WEB_COOKIE_PROVIDERS } = await import(
"../../src/shared/constants/providers/web-cookie.ts"
);
const { WEB_COOKIE_PROVIDERS } = await import("../../src/shared/constants/providers/web-cookie.ts");
// Sample JWT payload (unsigned shape for claim extraction only)
function makeFakeJwt(claims: Record<string, unknown>): string {
@@ -131,10 +129,10 @@ describe("PromptQl — helpers", () => {
);
}
if (!auth.includes(ddnLuxJwt)) {
return new Response(
JSON.stringify({ errors: [{ message: "unexpected token in test" }] }),
{ status: 200, headers: { "content-type": "application/json" } }
);
return new Response(JSON.stringify({ errors: [{ message: "unexpected token in test" }] }), {
status: 200,
headers: { "content-type": "application/json" },
});
}
return new Response(
JSON.stringify({
@@ -155,14 +153,23 @@ describe("PromptQl — helpers", () => {
const result = (await usage.getPromptQlUsage(sampleJwt, {
projectId: PROJECT_ID,
luxJwt: ddnLuxJwt,
})) as { quotas?: { credits?: { used?: number; remaining?: number; total?: number } }; message?: string };
assert.ok(result.quotas?.credits, `expected credits quota from luxJwt, got ${JSON.stringify(result)}`);
})) as {
quotas?: { credits?: { used?: number; remaining?: number; total?: number } };
message?: string;
};
assert.ok(
result.quotas?.credits,
`expected credits quota from luxJwt, got ${JSON.stringify(result)}`
);
assert.equal(result.quotas!.credits!.total, 50);
assert.equal(result.quotas!.credits!.used, 22);
assert.equal(result.quotas!.credits!.remaining, 28);
// First attempt should use luxJwt (DDN preferred over enrich apiKey)
assert.ok(calls.length >= 1);
assert.ok(calls[0]!.includes(ddnLuxJwt), `first call should use DDN luxJwt, got ${calls[0]?.slice(0, 80)}`);
assert.ok(
calls[0]!.includes(ddnLuxJwt),
`first call should use DDN luxJwt, got ${calls[0]?.slice(0, 80)}`
);
} finally {
globalThis.fetch = originalFetch;
}
@@ -241,9 +248,7 @@ describe("PromptQl — helpers", () => {
"USAGE_FETCHER_PROVIDERS must list promptql so generic quota fetcher can call it"
);
assert.ok((usageMain.USAGE_FETCHER_PROVIDERS as readonly string[]).includes("pql"));
const { USAGE_SUPPORTED_PROVIDERS } = await import(
"../../src/shared/constants/providers.ts"
);
const { USAGE_SUPPORTED_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
assert.ok(
(USAGE_SUPPORTED_PROVIDERS as readonly string[]).includes("promptql"),
"USAGE_SUPPORTED_PROVIDERS must list promptql for provider-limits sync"
@@ -252,7 +257,10 @@ describe("PromptQl — helpers", () => {
it("extracts OpenAI content-parts arrays", () => {
assert.equal(
mod.extractMessageText([{ type: "text", text: "hi" }, { type: "text", text: " there" }]),
mod.extractMessageText([
{ type: "text", text: "hi" },
{ type: "text", text: " there" },
]),
"hi\n there"
);
});
@@ -391,22 +399,10 @@ describe("PromptQl — thread continuity (no cross-chat sticky)", () => {
});
it("readClientThreadId accepts body and header variants", () => {
assert.equal(
mod.readClientThreadId({ promptql_thread_id: "t1" } as never),
"t1"
);
assert.equal(
mod.readClientThreadId({ thread_id: "t2" } as never),
"t2"
);
assert.equal(
mod.readClientThreadId({} as never, { "X-PromptQL-Thread-Id": "t3" }),
"t3"
);
assert.equal(
mod.readClientThreadId({} as never, { "x-conversation-id": "t4" }),
"t4"
);
assert.equal(mod.readClientThreadId({ promptql_thread_id: "t1" } as never), "t1");
assert.equal(mod.readClientThreadId({ thread_id: "t2" } as never), "t2");
assert.equal(mod.readClientThreadId({} as never, { "X-PromptQL-Thread-Id": "t3" }), "t3");
assert.equal(mod.readClientThreadId({} as never, { "x-conversation-id": "t4" }), "t4");
});
it("system messages do not collide independent user chats", () => {
@@ -528,10 +524,7 @@ describe("PromptQl — thread continuity (no cross-chat sticky)", () => {
it("normalizeForFingerprint strips agent_mention and User request wrappers", () => {
assert.equal(mod.normalizeForFingerprint("<agent_mention /> hello"), "hello");
assert.equal(
mod.normalizeForFingerprint("noise\n\nUser request:\nhello 2"),
"hello 2"
);
assert.equal(mod.normalizeForFingerprint("noise\n\nUser request:\nhello 2"), "hello 2");
});
});

View File

@@ -62,5 +62,8 @@ test("OpenAI -> Gemini request strips strict from OpenAI-style function tool par
const parameters = result.tools?.[0]?.functionDeclarations?.[0]?.parameters;
assert.ok(parameters, "expected a translated function declaration");
assert.ok(!JSON.stringify(parameters).includes("strict"), "strict must not reach the upstream request");
assert.ok(
!JSON.stringify(parameters).includes("strict"),
"strict must not reach the upstream request"
);
});

View File

@@ -1,4 +1,3 @@
import type { Response as Resp } from "undici";
// Minimal fetch mock responses that satisfy what apiFetch needs.
@@ -15,7 +14,7 @@ export function makeMcpResp(data: unknown, status = 200, headers: Record<string,
}
export function makeMcpStreamFetch({
toolResult = { content: [{ type: "text", text: "ok" }] },
toolResult = { ok: true },
initStatus = 200,
callStatus = 200,
callError = false,
@@ -28,12 +27,20 @@ export function makeMcpStreamFetch({
const body = init?.body ? JSON.parse(init.body) : {};
if (body.method === "initialize") {
return makeMcpResp(
{ jsonrpc: "2.0", id: body.id, result: { protocolVersion: "2024-11-05", capabilities: {} } },
{
jsonrpc: "2.0",
id: body.id,
result: { protocolVersion: "2024-11-05", capabilities: {} },
},
initStatus,
initStatus < 400 ? { "mcp-session-id": "sess-test" } : {},
initStatus < 400 ? { "mcp-session-id": "sess-test" } : {}
);
}
if (body.method === "tools/call") {
const headers = new Headers(init?.headers as HeadersInit | undefined);
if (headers.get("mcp-session-id") !== "sess-test") {
return makeMcpResp({ error: "Mcp-Session-Id header is required" }, 400);
}
if (callStatus !== 200) return makeMcpResp({ error: "tool failure" }, callStatus);
if (callError) {
return makeMcpResp({
@@ -42,7 +49,13 @@ export function makeMcpStreamFetch({
result: { content: [{ type: "text", text: "tool error" }], isError: true },
});
}
return makeMcpResp({ jsonrpc: "2.0", id: body.id, result: toolResult });
const result =
toolResult && typeof toolResult === "object" && "content" in toolResult
? toolResult
: {
content: [{ type: "text", text: JSON.stringify(toolResult) }],
};
return makeMcpResp({ jsonrpc: "2.0", id: body.id, result });
}
return makeMcpResp({ error: "unknown method" }, 400);
}) as unknown as typeof globalThis.fetch;

View File

@@ -7,23 +7,20 @@ import { fileURLToPath } from "node:url";
const repoRoot = join(dirname(fileURLToPath(import.meta.url)), "../..");
function readHomePage(): string {
return readFileSync(
join(repoRoot, "src/app/(dashboard)/home/page.tsx"),
"utf8",
);
return readFileSync(join(repoRoot, "src/app/(dashboard)/home/page.tsx"), "utf8");
}
function readReadinessCard(): string {
return readFileSync(
join(repoRoot, "src/app/(dashboard)/dashboard/FirstRunReadinessCard.tsx"),
"utf8",
"utf8"
);
}
function readEnKeys(): string[] {
const en = JSON.parse(
readFileSync(join(repoRoot, "src/i18n/messages/en.json"), "utf8"),
) as { home: Record<string, string> };
const en = JSON.parse(readFileSync(join(repoRoot, "src/i18n/messages/en.json"), "utf8")) as {
home: Record<string, string>;
};
return Object.keys(en.home);
}

View File

@@ -0,0 +1,24 @@
import assert from "node:assert/strict";
import test from "node:test";
import { executeImageWithCredentialFallback } from "../../src/sse/services/imageCredentialRetry.ts";
test("image credential retries stay within the connections advertising the endpoint model", async () => {
const allowedConnectionIds = ["image-a", "image-b"];
let observedAllowedConnectionIds: string[] | null | undefined;
const result = await executeImageWithCredentialFallback({
provider: "ollama-local",
requestedModel: "flux-dev",
allowedConnectionIds,
credentials: { connectionId: "image-a" },
execute: async () => ({ success: false, status: 401 }),
selectNextCredentials: async (_provider, _model, _excluded, allowed) => {
observedAllowedConnectionIds = allowed;
return null;
},
});
assert.deepEqual(observedAllowedConnectionIds, allowedConnectionIds);
assert.equal(result.result.status, 401);
});

View File

@@ -157,8 +157,10 @@ test("Ollama image model routes through its advertising connection", async () =>
]);
let capturedUrl = "";
globalThis.fetch = async (input) => {
let capturedBody: Record<string, unknown> = {};
globalThis.fetch = async (input, init = {}) => {
capturedUrl = String(input);
capturedBody = JSON.parse(String(init.body || "{}")) as Record<string, unknown>;
return Response.json({ data: [{ b64_json: "aW1hZ2U=" }] });
};
@@ -172,6 +174,7 @@ test("Ollama image model routes through its advertising connection", async () =>
assert.equal(response.status, 200, await response.text());
assert.equal(capturedUrl, "http://127.0.0.1:11435/v1/images/generations");
assert.equal(capturedBody.model, "image-model");
});
test("Ollama embedding model routes through its advertising connection", async () => {

View File

@@ -73,11 +73,7 @@ test("clamp: disable-shaped efforts map to low (upstream refuses to stop thinkin
for (const effort of ["none", "minimal"]) {
const body = { ...HERMES_BODY, reasoning_effort: effort };
const result = sanitizeReasoningEffortForProvider(body, "opencode-go", "ox-alpha-free", null);
assert.equal(
(result as Record<string, unknown>).reasoning_effort,
"low",
`${effort} → low`
);
assert.equal((result as Record<string, unknown>).reasoning_effort, "low", `${effort} → low`);
}
});
@@ -103,10 +99,12 @@ test("clamp writes back to every carrier present (top-level + reasoning.effort +
reasoning: { effort: "medium" },
output_config: { effort: "medium" },
};
const result = sanitizeReasoningEffortForProvider(body, "opencode-go", "ox-alpha-free", null) as Record<
string,
unknown
>;
const result = sanitizeReasoningEffortForProvider(
body,
"opencode-go",
"ox-alpha-free",
null
) as Record<string, unknown>;
assert.equal(result.reasoning_effort, "high");
assert.deepEqual(result.reasoning, { effort: "high" });
assert.deepEqual(result.output_config, { effort: "high" });
@@ -114,7 +112,12 @@ test("clamp writes back to every carrier present (top-level + reasoning.effort +
test("no declaration → pass-through unchanged (#8057 policy for unlisted models)", () => {
const body = { ...HERMES_BODY, model: "some-unregistered-model", reasoning_effort: "medium" };
const result = sanitizeReasoningEffortForProvider(body, "opencode-go", "some-unregistered-model", null);
const result = sanitizeReasoningEffortForProvider(
body,
"opencode-go",
"some-unregistered-model",
null
);
assert.equal(result, body, "undeclared models keep today's trust-the-upstream behavior");
assert.equal((result as Record<string, unknown>).reasoning_effort, "medium");
});

View File

@@ -866,7 +866,11 @@ test("OpenAI -> Antigravity maps Claude-family models to Gemini-compatible schem
assert.match(result.requestId, /^agent\/\d+\/[0-9a-f]{8}$/);
assert.equal(result.enabledCreditTypes, undefined);
assert.equal(result.request.systemInstruction.parts[0].text, ANTIGRAVITY_DEFAULT_SYSTEM);
assert.equal(result.request.systemInstruction.parts.length, 1, "systemInstruction must contain only ANTIGRAVITY_DEFAULT_SYSTEM (#9030)");
assert.equal(
result.request.systemInstruction.parts.length,
1,
"systemInstruction must contain only ANTIGRAVITY_DEFAULT_SYSTEM (#9030)"
);
// #9030 — Client system content moved to first user message to avoid upstream 429s
assert.equal(result.request.contents[0].parts[0].text, "Project rules");
assert.equal(result.request.contents[0].parts[1].text, "Read a file");

View File

@@ -1174,7 +1174,10 @@ test("Gemini stream: open textual reasoning is flushed before a signed native to
"buffered textual reasoning must be flushed, not dropped, when a tool call arrives"
);
assert.equal(r2[toolIdx]?.choices[0].delta.tool_calls[0].id, "call-flush-1");
assert.ok(reasoningIdx >= 0 && toolIdx > reasoningIdx, "reasoning is emitted before the tool call");
assert.ok(
reasoningIdx >= 0 && toolIdx > reasoningIdx,
"reasoning is emitted before the tool call"
);
});
// #3821-review LEDGER-15 — a reasoning-only chunk interrupting a partially-buffered

View File

@@ -1,8 +1,9 @@
/**
* Vertex AI Anthropic partner-model discovery (#11279).
*
* Covers the two pure units the PR adds (the discovery route itself is a
* best-effort network path exercised manually per the PR's test plan):
* Covers the pure discovery contracts (the route's external request remains a
* best-effort network path):
* - Model Garden PublisherModels URL: the documented v1beta1 global parent;
* - parseVertexAnthropicModels: Model Garden publisher response → discovery
* models, handling global AND project-scoped resource names;
* - getModelTargetFormat: a claude-* id on vertex/vertex-partner resolves to
@@ -12,12 +13,22 @@
import test from "node:test";
import assert from "node:assert/strict";
import { parseVertexAnthropicModels } from "../../src/lib/providerModels/vertexAnthropicModelsParser.ts";
import {
parseVertexAnthropicModels,
VERTEX_ANTHROPIC_PUBLISHER_MODELS_URL,
} from "../../src/lib/providerModels/vertexAnthropicModelsParser.ts";
import { getModelTargetFormat } from "../../open-sse/config/providerModels.ts";
test("Vertex Anthropic discovery uses the v1beta1 PublisherModels list endpoint", () => {
assert.equal(
VERTEX_ANTHROPIC_PUBLISHER_MODELS_URL,
"https://aiplatform.googleapis.com/v1beta1/publishers/anthropic/models"
);
});
test("parseVertexAnthropicModels: global publisher resource names", () => {
const out = parseVertexAnthropicModels({
models: [
publisherModels: [
{
name: "publishers/anthropic/models/claude-sonnet-4-6",
displayName: "Claude Sonnet 4.6",
@@ -42,7 +53,7 @@ test("parseVertexAnthropicModels: global publisher resource names", () => {
test("parseVertexAnthropicModels: project-scoped resource names strip the prefix", () => {
const out = parseVertexAnthropicModels({
models: [
publisherModels: [
{
name: "projects/my-gcp-project/locations/us-east5/publishers/anthropic/models/claude-haiku-4-5",
},
@@ -55,9 +66,32 @@ test("parseVertexAnthropicModels: project-scoped resource names strip the prefix
test("parseVertexAnthropicModels: malformed input yields an empty list", () => {
assert.deepEqual(parseVertexAnthropicModels(null), []);
assert.deepEqual(parseVertexAnthropicModels(42), []);
assert.deepEqual(parseVertexAnthropicModels("not-an-envelope"), []);
assert.deepEqual(parseVertexAnthropicModels([]), []);
assert.deepEqual(parseVertexAnthropicModels({}), []);
assert.deepEqual(parseVertexAnthropicModels({ models: "not-an-array" }), []);
assert.deepEqual(parseVertexAnthropicModels({ models: [{ name: "" }, {}] }), []);
assert.deepEqual(
parseVertexAnthropicModels({
models: [{ name: "publishers/anthropic/models/claude-wrong-envelope" }],
}),
[]
);
assert.deepEqual(parseVertexAnthropicModels({ publisherModels: "not-an-array" }), []);
assert.deepEqual(parseVertexAnthropicModels({ publisherModels: [{ name: "" }, {}] }), []);
assert.deepEqual(
parseVertexAnthropicModels({
publisherModels: [null, 42, "invalid", { name: "publishers/anthropic/models/claude-valid" }],
}),
[
{
id: "claude-valid",
name: "claude-valid",
supportedEndpoints: ["chat"],
targetFormat: "claude",
owned_by: "anthropic",
},
]
);
});
test("getModelTargetFormat: claude-* on vertex resolves to the claude translator (heuristic)", () => {