Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
ed3e283
chore(release): open v3.8.27 development cycle
diegosouzapw Jun 16, 2026
135f40e
ci(security): harden workflows — artipacked persist-credentials + cac…
diegosouzapw Jun 16, 2026
cc5735c
feat: add sidebar group separator toggles (#3971)
rdself Jun 16, 2026
32257d4
Gate control-plane proxy direct fallback (#3963)
rdself Jun 16, 2026
80137c6
Capture actual upstream provider requests (#3941)
rdself Jun 16, 2026
e799397
ci(quality): flip require-tighten + osv + Trivy to blocking (v3.8.27 …
diegosouzapw Jun 16, 2026
cfba9e3
fix(resilience): respect connection cooldown stored as numeric epoch …
diegosouzapw Jun 16, 2026
74ea71a
fix(providers): fetch live /models for LLM7 and BytePlus (#3976) (#3996)
diegosouzapw Jun 16, 2026
4fe7f27
fix(dashboard): logs auto-refresh reads live visibility, not a stale …
diegosouzapw Jun 16, 2026
e20081c
fix(combo): shuffle strict-random fallback remainder to spread load (…
diegosouzapw Jun 16, 2026
3f47bdd
Add provider auth visibility controls (#3953)
rdself Jun 16, 2026
bec5bd2
fix(claude): forward client tool-search-tool anthropic-beta on the Cl…
diegosouzapw Jun 16, 2026
bdee649
fix(db): persist backup retention days (#3970)
rdself Jun 16, 2026
225f617
大量UI显示和i18n优化 (#3973)
rdself Jun 16, 2026
fba3d34
deps: bump the npm_and_yarn group across 1 directory with 2 updates (…
dependabot[bot] Jun 16, 2026
1bac029
deps: bump form-data from 4.0.5 to 4.0.6 (#3944)
dependabot[bot] Jun 16, 2026
f12b5af
deps: bump vite from 8.0.5 to 8.0.16 (#3942)
dependabot[bot] Jun 16, 2026
4540320
chore(quality): re-baseline validation.ts 4407->4428 (#3958 qwen body…
diegosouzapw Jun 16, 2026
6885c1b
deps: bump the production group with 13 updates (#3915)
dependabot[bot] Jun 16, 2026
e682f7c
fix(perplexity-web): parse schematized diff_block stream so answers a…
artickc Jun 16, 2026
9bfda37
refactor: modularize providerRegistry.ts into 159 individual provider…
oyi77 Jun 16, 2026
a581c1f
fix(registry): restore byteplus + mimocode dropped by #3993 modulariz…
diegosouzapw Jun 16, 2026
1510b08
refactor: modularize schemas (non-stacked) (#3988)
oyi77 Jun 16, 2026
3683065
feat(openai): honor custom base URL in model discovery + complete ope…
artickc Jun 16, 2026
5de0fc0
fix(live-ws): bridge sidecar events to dashboard (#4004)
megamen32 Jun 16, 2026
d0700a9
fix(repo): untrack accidentally-committed root node_modules symlink +…
diegosouzapw Jun 16, 2026
2700f51
feat(sse): real LLMLingua-2 ONNX compression engine (stable) (#4014)
diegosouzapw Jun 16, 2026
54902f9
test(dashboard): rehome #3972 logs auto-refresh test so a runner coll…
diegosouzapw Jun 16, 2026
6ab596f
feat(compression): capture per-engine analytics (#3960) + Lite schema…
diegosouzapw Jun 16, 2026
e715181
fix(sse): guard model-less registry entries in getUnsupportedParams (…
diegosouzapw Jun 16, 2026
92769ce
feat(ci): Quality Gate v2 — Onda 0 + Onda 1 (gate flips, TIA, SAST, D…
diegosouzapw Jun 16, 2026
61efe8e
fix(sse): preserve Kiro streaming finish_reason tool_calls (#3980) (#…
diegosouzapw Jun 16, 2026
2e3b6d4
fix(guardrails): preserve original image when vision-bridge describe …
diegosouzapw Jun 16, 2026
e7f42d8
feat(api): advertise combo capabilities on import surfaces (#3979) (#…
diegosouzapw Jun 16, 2026
6f3e215
feat(sse): delegated Anthropic Context Editing for Claude (clear_tool…
diegosouzapw Jun 16, 2026
66ef036
fix(opencode): map x-session-affinity to x-opencode-session for custo…
diegosouzapw Jun 16, 2026
261f609
fix(dashboard): Playground Compare tab loading + HTTP method guard (#…
rdself Jun 16, 2026
150133c
refactor(dashboard): settings UI layout + API Keys naming (#4020)
rdself Jun 16, 2026
fe5ca07
fix: restore unit regressions dropped by lossy schema/registry modula…
diegosouzapw Jun 16, 2026
f5b78e2
refactor: modularize open-sse/services/combo.ts (Issue #3594)
oyi77 Jun 11, 2026
bf41057
fix: gut open-sse/services/combo.ts to re-export
oyi77 Jun 17, 2026
3ae559e
fix: address review feedback
oyi77 Jun 17, 2026
5670ce5
refactor: split oversized file per 800-line cap requirement
oyi77 Jun 17, 2026
c80ce68
refactor: split oversized file per 800-line cap requirement
oyi77 Jun 17, 2026
73629b3
split(chat.ts): refactor 1574-line handleComboChat into modular sub-s…
oyi77 Jun 17, 2026
7b1eaa2
refactor: split combo/chat.ts per 800-line new-file cap
oyi77 Jun 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ jobs:
actions: read
contents: read
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: github/codeql-action/init@dd903d2e4f5405488e5ef1422510ee31c8b32357 # v3
- uses: github/codeql-action/init@v3
with:
languages: javascript-typescript
queries: security-extended
- uses: github/codeql-action/analyze@dd903d2e4f5405488e5ef1422510ee31c8b32357 # v3
- uses: github/codeql-action/analyze@v3
with:
category: "/language:javascript-typescript"
8 changes: 4 additions & 4 deletions .github/workflows/dast-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ jobs:
JWT_SECRET: ci-build-secret-with-sufficient-length-for-validation
API_KEY_SECRET: ci-api-key-secret-with-sufficient-length-aaaa
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
- uses: actions/setup-node@v4
with:
node-version: "24"
cache: npm
Expand All @@ -36,7 +36,7 @@ jobs:
if curl -sf http://localhost:20128/api/monitoring/health >/dev/null; then echo up; break; fi
sleep 2
done
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install schemathesis
Expand All @@ -54,7 +54,7 @@ jobs:
- name: Stop server
if: always()
run: kill "$(cat server.pid)" || true
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
- uses: actions/upload-artifact@v4
if: always()
with:
name: dast-smoke-logs
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ jobs:
- name: Trivy image scan (SARIF, advisory)
if: needs.prepare.outputs.version != 'main'
continue-on-error: true
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
uses: aquasecurity/trivy-action@v0.36.0
with:
image-ref: ${{ env.GHCR_IMAGE_NAME }}:${{ env.VERSION }}
format: sarif
Expand All @@ -366,7 +366,7 @@ jobs:
# note in docs/security/SUPPLY_CHAIN.md).
- name: Trivy CRITICAL gate (blocking)
if: needs.prepare.outputs.version != 'main'
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
uses: aquasecurity/trivy-action@v0.36.0
with:
image-ref: ${{ env.GHCR_IMAGE_NAME }}:${{ env.VERSION }}
format: table
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/nightly-mutation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
cache: npm
- run: npm ci
- name: Restore Stryker incremental cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
uses: actions/cache@v4
with:
path: reports/mutation/stryker-incremental.json
key: stryker-incremental-${{ github.run_id }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/semgrep.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
container:
image: semgrep/semgrep
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Run semgrep (advisory)
Expand All @@ -21,7 +21,7 @@ jobs:
semgrep scan --config p/owasp-top-ten --config p/secrets \
--sarif --output semgrep.sarif --metrics off || true
python -c "import json; d=json.load(open('semgrep.sarif')); print('semgrepFindings=%d' % len(d['runs'][0]['results']))" || echo "semgrepFindings=SKIP"
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
- uses: actions/upload-artifact@v4
if: always()
with:
name: semgrep-sarif
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ _In development — bullets added per PR; finalized at release._
- **fix(dashboard): refine the provider quota card display** — the provider quota card layout was refined for clearer quota/usage presentation. ([#3969](https://github.com/diegosouzapw/OmniRoute/pull/3969) — thanks @rdself)
- **fix(dashboard): refine compression settings, storage labels, and sidebar grouping** — polishes the compression-settings UI, clarifies storage labels, and tidies the sidebar grouping. ([#4033](https://github.com/diegosouzapw/OmniRoute/pull/4033) — thanks @rdself)

### ✨ New Features

- **feat(combos): advertise combo capabilities (multimodal / reasoning / caching) on the import surfaces** — importing a combo package into a client (LobeHub / OpenCode / VS Code, via `/v1/combos` and the VS Code combo catalog) no longer requires manually enabling multimodal/image-input, reasoning, and caching afterwards. `projectCombo` now attaches a registry-derived `capabilities` block, gated conservatively: `multimodal`/`reasoning` are advertised only when **every** concrete model step proves the capability (an unprovable nested combo-ref drops them, since the strategy may route to any member), and `caching` reflects the combo's explicit Context-Cache-Protection setting (no surprise prompt-cache cost). The public `/v1/combos` default projection (#2300) is unchanged unless the caller opts in. ([#3979](https://github.com/diegosouzapw/OmniRoute/issues/3979) — thanks @xenstar)

### 🔒 Security & Hardening

- **fix(security): eliminate a polynomial ReDoS in the combo `<omniModel>` tag regex** — `comboAgentMiddleware`'s cache-tag pattern wrapped the tag in an unbounded newline run (`(?:\n|\r)*`), making `.test()` / `.replace()` run in O(n²) on inputs with many newlines (CodeQL `js/polynomial-redos`). The detection pattern now matches only the core `<omniModel>…</omniModel>` and the global strip pattern bounds the surrounding newline runs, keeping it linear; detection / extraction / multi-tag stripping behavior is unchanged. ([#3982](https://github.com/diegosouzapw/OmniRoute/pull/3982) — thanks @diegosouzapw)
Expand All @@ -74,6 +78,12 @@ _In development — bullets added per PR; finalized at release._
- **docs(troubleshooting): note that the MITM proxy cannot intercept Windows-host apps under WSL** — documents that the MITM proxy running inside WSL cannot intercept traffic from apps on the Windows host. ([#4003](https://github.com/diegosouzapw/OmniRoute/pull/4003) — thanks @diegosouzapw)
- **chore(quality): maintenance roll-up** — assorted quality-gate hygiene that does not change runtime behavior: re-baseline `validation.ts` for the #3958 qwen body-check, allowlist the `socks` dependency declared by #4004, ignore jscpd major bumps (the v5 Rust rewrite breaks the pinned duplication gate), untrack an accidentally-committed root `node_modules` symlink (and gitignore it), rehome the #3972 logs auto-refresh test so a runner collects it, and open the v3.8.27 development cycle. (thanks @diegosouzapw)

### 🐛 Fixed

- **fix(opencode): forward the OpenCode session id to the upstream regardless of how the user named the provider** — the `OpencodeExecutor` forwarded the `x-opencode-session/request/project/client` headers, but the OpenCode CLI only emits those when the configured `providerID` **starts with** `"opencode"`. A user who adds OmniRoute as a custom provider (e.g. `"omniroute"`) makes the CLI send `x-session-affinity` / `X-Session-Id` instead (both carry the same session id), which the executor never read — so the session-metadata forwarding was effectively dead code for the realistic provider-naming case. The opencode-family executor now falls back to `x-session-affinity` / `X-Session-Id` and maps it onto `x-opencode-session` when the client didn't send the header directly, so session continuity to the `opencode.ai` upstream works for any provider name (a direct `x-opencode-session` still wins). Scoped to this executor only — the generic `DefaultExecutor` intentionally does **not** do this, to avoid leaking the client session id to arbitrary third-party upstreams. ([#4022](https://github.com/diegosouzapw/OmniRoute/issues/4022) — thanks @pizzav-xyz)
- **fix(guardrails): Vision Bridge no longer drops the image when the describe call fails (Nvidia NIM "Image unavailable")** — the Vision Bridge is enabled by default and engages for any model whose vision capability OmniRoute can't prove from the registry (`supportsVision !== true`, which includes uncatalogued models that resolve to `null`). When the per-image describe call failed (e.g. no vision model configured), it replaced the image with the literal text `[Image N]: (unavailable)` and dropped the original `image_url` — so a genuinely vision-capable upstream (Nvidia NIM) received text only and answered "Image unavailable. Cannot provide description without visual data." A describe failure is no longer destructive: `replaceImageParts` now receives `null` for failed images and **preserves the original image part** so the upstream can still see it (successful describes still replace the image with the text description; `meta.descriptions` observability is unchanged). ([#4012](https://github.com/diegosouzapw/OmniRoute/issues/4012) — thanks @daniij)
- **fix(kiro): preserve `finish_reason: "tool_calls"` on the Kiro streaming path** — streaming tool-call requests through the Kiro (Responses API) provider had their terminal `finish_reason` reported as `"stop"` instead of `"tool_calls"`, so agent clients (Hermes) treated the tool-call turn as a finished turn, never ran the tool, and the next request failed with HTTP 400 on the incomplete tool state. `convertKiroToOpenAI`'s terminal `messageStopEvent`/`done` branch hardcoded `finish_reason: "stop"` regardless of whether the stream had emitted `toolUseEvent`s. The translator now records `state.sawToolUse` when a tool-use chunk is emitted and reports `finish_reason: "tool_calls"` on the terminal chunk (and in `state.finishReason`) whenever the stream produced tool calls. The non-streaming path was already correct. ([#3980](https://github.com/diegosouzapw/OmniRoute/issues/3980) — thanks @lordavadon2)

---

## [3.8.26] — 2026-06-15
Expand Down
8 changes: 3 additions & 5 deletions config/quality/file-size-baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
"_rebaseline_2026_06_16_3960_engine_breakdown": "PR #3960 capture own growth: chatCore.ts 5851->5868 (+17 = persist result.stats.engineBreakdown into the new compression_engine_breakdown table after a stacked compression run, so getPerEngineAnalytics is accurate historically and not live-only). Cohesive analytics-persistence at the existing compression chokepoint; structural shrink of chatCore.ts tracked in #3501.",
"_rebaseline_2026_06_15_3938_perplexity_v218": "PR #3938 own growth: perplexity-web.ts 868->939 (+71 = rebuild buildPplxRequestBody to mirror the current www.perplexity.ai schematized request body — version 2.18, use_schematized_api + the full supported_block_use_cases list, dsl_query, shared requestId for frontend_uuid/client_search_results_cache_key, last_backend_uuid only on follow-ups — plus the x-perplexity-request-* / x-request-id headers replacing the stale X-App-ApiVersion pair that triggered HTTP 400). Cohesive upstream-schema sync in a single executor; not extractable.",
"_rebaseline_2026_06_16_4021_context_editing": "PR #4021 own growth: base.ts 1222->1244 (+22 = inject delegated Context Editing at the single Claude pre-serialization chokepoint — applyContextEditingToBody() call gated to the genuine `claude` provider, the contextEditing field on ExecuteInput, its destructure, and a debug log) and chatCore.ts 5868->5875 (+7 = capture contextEditing.enabled at the canonical compression-settings read into a function-scoped flag, threaded to the two executor.execute() callsites). The reusable edit-builder + strategy constants live in the new small open-sse/config/contextEditing.ts (well under cap). Cohesive opt-in feature at the existing dispatch chokepoint; not extractable without hiding the Claude body-finalization boundary.",
"_rebaseline_2026_06_16_4033_compression_token_saver_ui": "PR #4033 net -46 LOC overall: CompressionSettingsTab.tsx 932->974 (+42 over frozen after relocating Token Saver from Endpoint/Appearance into Compression Settings). This is a deliberate UI ownership redistribution, not aggregate code growth; keeping the control with the compression settings makes the module boundary clearer.",
"_rebaseline_2026_06_17_4034_usage_command": "PR #4034 own growth: apiKeys.ts 1633->1661 (+28 = the allow_usage_command additive column — fallback definition, parseAllowUsageCommand, prepared-statement SELECT column, and the metadata/create/update wiring, mirroring the existing disable_non_public_models accessor pattern) and chat.ts 1425->1432 (+7 = the handleInternalUsageCommand intercept hook at the existing post-auth chokepoint in handleChat). The reusable command logic lives in the new src/lib/usage/internalUsageCommand.ts (well under cap). Cohesive opt-in feature at the established column/dispatch boundaries; not extractable without splitting the api-keys domain module.",
"cap": 800,
"frozen": {
"open-sse/config/providerRegistry.ts": 4731,
Expand Down Expand Up @@ -86,7 +84,7 @@
"src/app/(dashboard)/dashboard/providers/page.tsx": 1925,
"src/app/(dashboard)/dashboard/runtime/RuntimePageClient.tsx": 1198,
"src/app/(dashboard)/dashboard/settings/components/AppearanceTab.tsx": 819,
"src/app/(dashboard)/dashboard/settings/components/CompressionSettingsTab.tsx": 974,
"src/app/(dashboard)/dashboard/settings/components/CompressionSettingsTab.tsx": 932,
"src/app/(dashboard)/dashboard/settings/components/MemorySkillsTab.tsx": 880,
"src/app/(dashboard)/dashboard/settings/components/PricingTab.tsx": 1012,
"src/app/(dashboard)/dashboard/settings/components/ProxyRegistryManager.tsx": 1089,
Expand All @@ -102,7 +100,7 @@
"src/app/api/usage/analytics/route.ts": 941,
"src/app/api/v1/models/catalog.ts": 1435,
"src/lib/cloudflaredTunnel.ts": 934,
"src/lib/db/apiKeys.ts": 1661,
"src/lib/db/apiKeys.ts": 1633,
"src/lib/db/core.ts": 1820,
"src/lib/db/migrationRunner.ts": 1125,
"src/lib/db/models.ts": 1180,
Expand All @@ -127,7 +125,7 @@
"src/shared/constants/sidebarVisibility.ts": 1100,
"src/shared/services/cliRuntime.ts": 1090,
"src/shared/validation/schemas.ts": 2523,
"src/sse/handlers/chat.ts": 1432,
"src/sse/handlers/chat.ts": 1425,
"src/sse/services/auth.ts": 2219
},
"_rebaseline_2026_06_09": "Re-baseline consciente pre-release v3.8.19: 9 arquivos cresceram durante o ciclo (features mergeadas: RequestLoggerV2 +281 request-logger rework, stream +101, combo +73, chatCore +45, catalog +32 fable-5/catalog-flag, callLogs +4, accountFallback +2, usageHistory novo 840) + core.ts +7 (fix resetAllDbModuleState, PR 3536). A catraca segue valendo destes valores — proximo crescimento falha. Decisao: encolher (esp. RequestLoggerV2/chatCore) e a issue #3501 ficam para o ciclo seguinte.",
Expand Down
Loading
Loading