Commit Graph

4590 Commits

Author SHA1 Message Date
Diego Rodrigues de Sa e Souza
d055b5b8fc fix(dashboard): make provider card hover visible (was ~invisible 1% opacity) (#4214)
Integrated into release/v3.8.29 (round 8)
2026-06-18 20:50:14 -03:00
Diego Rodrigues de Sa e Souza
fe548212a4 docs(api): document /api/v1/ws chat WebSocket endpoint in openapi.yaml (#4215)
Integrated into release/v3.8.29 (round 8)
2026-06-18 20:50:12 -03:00
Diego Rodrigues de Sa e Souza
1cdbf73925 feat(compression): show an engine node for single-engine runs in the studio (#4210)
Integrated into release/v3.8.29 (round 7). Studio shows a real engine node for single-engine compression runs via ensureEngineBreakdown (new pure leaf engineBreakdown.ts). Reconciled the file-size baseline (chatCore.ts 5060->5063) + union-merged with the #4202 zenmux rebaseline key after release drift. Validated locally: file-size gate OK + 3/3 tests + typecheck:core clean.
2026-06-18 20:23:01 -03:00
Diego Rodrigues de Sa e Souza
6a64bad16b fix(providers): ZenMux model discovery serves the live catalog incl. free models (#4202) (#4213) 2026-06-18 20:20:45 -03:00
Diego Rodrigues de Sa e Souza
cfc2bc707b feat(dashboard): derive media serviceKinds from registries (surface MiniMax + media catalog) (#4212)
Integrated into release/v3.8.29 (round 7). Media serviceKinds derived from backend registries (single source of truth) unioned with declared kinds; listing + detail pages use the same resolver (no 'listed but 404'). Surfaces MiniMax (tts/video/music) + ~48 previously-invisible media providers. Validated locally: 6/6 tests + typecheck:core clean.
2026-06-18 20:19:00 -03:00
Diego Rodrigues de Sa e Souza
12124aaad8 feat(mitm): local-only route + trust-store installer for TPROXY decrypt (4b/N) (#4211)
Integrated into release/v3.8.29 (round 7). TPROXY decrypt 4b/N: local-only route (/api/tools/agent-bridge/tproxy, LOCAL_ONLY per routeGuard) + dedicated trust-store CA installer (execFileWithPassword, no shell). Validated locally: 12/12 tests + typecheck:core clean (test-unit does not run on release PRs).
2026-06-18 20:18:01 -03:00
Diego Rodrigues de Sa e Souza
8a0863c5a8 chore(ci): add quota + 6 covered chatCore leaves to stryker mutate (QG v2 Fase 9 T5 Fase 3 follow-up) (#4209)
Integrated into release/v3.8.29 (round 7). CI-only: stryker mutate += quotaScoring/quotaStrategies (batch f) + 6 covered chatCore leaves (batch g); nightly matrix 5->7 batches. Follow-up to #4205/#4204.
2026-06-18 20:16:47 -03:00
Diego Rodrigues de Sa e Souza
4c6cb45a6a feat(mitm): TPROXY capture-mode manager (decrypt 4a/N) (#4208)
Singleton lifecycle around the decrypt-capable transparent listener (#4200):
builds the dynamic CA (#4173), gates on native-addon availability, holds the
single running handle, counts interceptions, and exposes start / stop / status
for a local-only route (4b) to drive.

The OS trust-store mechanism is deliberately not baked in: installCa / uninstallCa
are injected by the caller (the route / VPS e2e provides the real installer, which
needs its own trust-store slot so it does not clobber the static MITM cert). The
manager therefore never mutates the trust store itself and stays unit-testable
without root or the native addon.

- startCaptureMode: rejects when unavailable or already running; builds the CA;
  wires the injected installCa/uninstallCa through to the decrypt listener.
- stopCaptureMode: stops the handle (close + uninstall CA + revert), idempotent.
- getCaptureStatus: running / available / startedAt / interceptCount / onPort.

Route + real trust-store installer + Traffic Inspector UI tab + VPS
e2e-with-decrypt + addon prebuilds follow (4b+).
2026-06-18 19:21:16 -03:00
Diego Rodrigues de Sa e Souza
4fecb34ac6 fix(compression): bound mcpAccessibility maxTextChars on the live read path (#4206)
* fix(compression): bound mcpAccessibility maxTextChars on the live read path

smartFilterText reserves 300 chars for the truncation tail, so a maxTextChars at/below that
makes headSize <= 0 and the whole tool result is replaced by the notice (total data loss). Two
gaps let a bad value reach the engine: the DB normalizer floored maxTextChars only at > 0, and
the live MCP-server read path (readMcpAccessibilityConfig) did a raw {...DEFAULT, ...parsed}
spread with no bounding at all.

Centralize the floors in a shared clampMcpAccessibilityConfig (engine layer) used by both the DB
normalizer and the server read path; values in (0, 600) fall back to the default. Export the
tail-reserve constant (300) and use it in smartFilterText so the engine and the bounds stay in
sync. The F5.3 headSize >= 0 clamp stays as a second layer.

Defense-in-depth today (the config isn't writable via the settings API yet — making it
configurable is a tracked follow-up in the compression-completeness work); this closes the
data-loss path for when it lands.

Part of the compression "100% functional" program (audit follow-up).

* chore(quality): bump server.ts file-size baseline 1457->1458 (#4206 +1 import)
2026-06-18 19:14:13 -03:00
Diego Rodrigues de Sa e Souza
aed2a5024c feat(compression): persist RTK grouping config (unlock R5 enableGrouping) (#4207)
The RTK R5 grouping strategy (collapse near-equivalent consecutive lines) is read by the
engine (config.enableGrouping / groupingThreshold) but was unreachable in production: the
rtkConfigSchema (.strict()) rejected the two fields on write and normalizeRtkConfig dropped
them on read, so they could never be anything but undefined.

Add enableGrouping (bool) + groupingThreshold (int, 2..100, default 3) to DEFAULT_RTK_CONFIG,
normalizeRtkConfig, and rtkConfigSchema so the feature is actually settable and survives the
DB round-trip. Default stays OFF — no behavior change for existing configs.

Part of the compression "100% functional" program (audit follow-up).
2026-06-18 19:12:27 -03:00
Diego Rodrigues de Sa e Souza
8e921cab4b chore(ci): re-add 8 combo split leaves to stryker mutate + expand nightly batch-matrix 3->5 (QG v2 Fase 9 T5 Fase 3) (#4205) 2026-06-18 19:12:22 -03:00
Diego Rodrigues de Sa e Souza
b05bc7469e fix(compression): harden RTK raw-output redaction + ReDoS guard for custom filters (F5.3) (#4203)
* fix(compression): broaden RTK raw-output secret redaction (Basic/Proxy auth + keys)

F5.3 follow-up. SECRET_PATTERNS missed Authorization / Proxy-Authorization with
Basic (curl -v emits "Basic <base64>") and credential field names that don't
contain token/secret/password as a substring (private_key, access_key, credential).
Add a (Proxy-)Authorization Bearer|Basic pattern and broaden the key-name
alternation. All patterns are flat (no nested quantifiers → no ReDoS).

* fix(compression): drop ReDoS-prone patterns from custom RTK filters

F5.3 follow-up. Custom filters (DATA_DIR/rtk/filters.json) carry user-supplied
regex strings compiled and run against untrusted tool output; a nested unbounded
quantifier ((a+)+, (a*)*, ([a-z]+)+ …) can cause catastrophic backtracking.
validateRtkFilter now drops such patterns via a conservative, dependency-free
heuristic (isReDoSProne) applied to every regex-bearing array in the canonical and
legacy filter shapes. safe-regex would be ideal but is not installable in this
symlinked worktree; the heuristic catches the common single-group nested-quantifier
shapes and is itself linear.

Surfaced (not fixed here): a canonical pack filter omitting `preserve` crashes
validateRtkFilter because rtkFilterPreserveSchema.default({}) leaves the inner arrays
undefined — tracked as a pre-existing fragility.
2026-06-18 19:12:17 -03:00
Diego Rodrigues de Sa e Souza
565eb281a7 refactor(combo): extract reset-aware quota block to combo/quotaStrategies.ts (QG v2 Fase 9 T5 D7b) (#4204) 2026-06-18 19:12:07 -03:00
Diego Rodrigues de Sa e Souza
3135be8e7b feat(mitm): wire TLS decrypt engine into TPROXY capture mode (decrypt 3/N) (#4200)
Integrated into release/v3.8.29 — wire TLS decrypt engine into TPROXY capture (opt-in decrypt mode, symmetric CA install/uninstall). 9/9 tests.
2026-06-18 17:08:14 -03:00
Diego Rodrigues de Sa e Souza
9229ac757d feat(api): expand zai provider catalog with GLM-5.2 / GLM-4.7 (#4201)
Integrated into release/v3.8.29 — zai catalog GLM-5.2/4.7 base models (effort aliases stay on glm). 4/4 tests.
2026-06-18 17:08:10 -03:00
Diego Rodrigues de Sa e Souza
f06a90d37f refactor(combo): extract round-robin sticky state to combo/rrState.ts (QG v2 Fase 9 T5 D7a) (#4196)
Integrated into release/v3.8.29 — D7a round-robin sticky state extracted byte-identically to combo/rrState.ts; reconciled with #4194 (baseline combo.ts -> 3398, resolving the over-cap left by #4194).
2026-06-18 17:03:47 -03:00
Diego Rodrigues de Sa e Souza
7e534d6a86 fix(compression): harden engines against I/O failures and misconfig (F5.3) (#4198)
Integrated into release/v3.8.29 — F5.3 compression engine hardening (registry re-register, headSize clamp, RTK readdir/write guards). 9/9 tests.
2026-06-18 17:02:50 -03:00
Svetznaniy33
02146ab4e9 fix(combo): keep passthrough quota fallback scoped (#4194)
Integrated into release/v3.8.29 — reconciled onto post-split combo.ts (#4186); RED->GREEN validated. Thanks @Svetznaniy33.
2026-06-18 16:54:09 -03:00
Diego Rodrigues de Sa e Souza
487621046f refactor(chatcore): extract combo/proxy context cache + semaphore helpers (QG v2 Fase 9 T5 C6-C7) (#4193)
Integrated into release/v3.8.29 — reconciled with #4188 (chatCore split part A): both byte-identical extractions stacked; baseline chatCore.ts -> 5060.
2026-06-18 16:45:28 -03:00
Diego Rodrigues de Sa e Souza
cd60eb20a9 test(compression): close F5.1 coverage gaps (replay reducer, live accumulator, StatusDot) (#4192)
Integrated into release/v3.8.29
2026-06-18 16:32:36 -03:00
Diego Rodrigues de Sa e Souza
4f3a113471 docs(readme): expand Acknowledgments into a themed, star-counted credits hall (#4195)
Integrated into release/v3.8.29
2026-06-18 16:28:12 -03:00
Demiurge The Single
31f519b9b0 fix(models): expose combo model token limits (#4189)
Integrated into release/v3.8.29. Thanks @megamen32! Reconciled on your branch: the branch had drifted behind release and would have reverted the centralized vision detection (#4072), the no-thinking gateway variants (#4145) and #4164's auto/* loop — those are kept, and your genuine improvement is applied on top: each auto/* /v1/models entry now carries advertised context/output limits + capabilities (createBuiltinAutoCombo, with a fallback to the minimal entry on resolve failure). Added a regression test (Rule #18) and bumped the catalog.ts file-size baseline 1440→1463 with justification.
2026-06-18 16:00:27 -03:00
Diego Rodrigues de Sa e Souza
0abe9a3a40 refactor(combo): god-file split part 3 — auto strategy (QG v2 Fase 9 T5 D8) (#4186)
Integrated into release/v3.8.29. combo god-file split part 3 (QG v2 Fase 9 T5 D8, reduced): auto-strategy scoring/intent/tag-routing/candidate-pool/quota-soft registry extracted byte-identically to open-sse/services/combo/autoStrategy.ts (434 LOC, <cap); buildAutoCandidates kept in combo.ts to avoid a combo⇄autoStrategy cycle; 4 public symbols re-exported. Validated: lint clean, file-size OK (combo.ts 3819→3432), check:cycles OK, autoStrategy has no combo-barrel import, 16/16 re-export tests.
2026-06-18 15:45:22 -03:00
Diego Rodrigues de Sa e Souza
647cb6a006 refactor(chatcore): extract passthrough/header/telemetry helpers (QG v2 Fase 9 T5 C2-C3-C5) (#4188)
Integrated into release/v3.8.29. chatCore god-file split Fase 2 part A (QG v2 Fase 9 T5 C2-C3-C5): 3 byte-identical leaf modules (passthroughHelpers/responseHeaders/telemetryHelpers) under open-sse/handlers/chatCore/; chatCore.ts re-exports the 5 previously-public symbols so existing importers resolve. Validated: lint clean, file-size OK (chatCore 5445→5265), 108/109 symbol-importer tests (the 1 fail = known executor-200ms timing flake under load; 65/65 clean on isolated re-run).
2026-06-18 15:33:10 -03:00
Diego Rodrigues de Sa e Souza
0a3b1de25a test(sse): guard Antigravity _toolNameMap through request-capture round-trip (#4181) (#4191)
Follow-up to #4091/#4153: the generic capture re-attach in
createPreparedRequestLogger().body() was only regression-tested on the
native-Claude OAuth cloak. Add a dedicated test driving the real
cloakAntigravityToolPayload (_ide suffix scheme) through the
JSON.parse(JSON.stringify()) capture round-trip, asserting the reverse
map survives, stays non-enumerable, and that all-native traffic yields no
spurious map. Proven RED with the #4153 re-attach removed. No production
change.

Closes #4181
2026-06-18 15:12:13 -03:00
Diego Rodrigues de Sa e Souza
ceb7e73df6 feat(memory): opt-in sqlite-vec int8 vector quantization (F4.4 Q2) (#4190)
Integrated into release/v3.8.29. Opt-in sqlite-vec int8 storage quantization (F4.4 Q2) via MEMORY_VEC_QUANTIZATION=int8; signature-gated so flipping mode triggers a reindex; default unchanged. Validated: node test 3/3 (incl. real int8 recall = exact float32 NN), file-size OK, lint clean.
2026-06-18 15:10:49 -03:00
Diego Rodrigues de Sa e Souza
0df3131fff feat(memory): opt-in Qdrant scalar int8 quantization (F4.4 Q1) (#4187)
Integrated into release/v3.8.29. Opt-in Qdrant scalar int8 quantization (F4.4 Q1); default 'none' keeps the create body byte-identical. Validated: vitest 9/9, file-size OK, lint clean.
2026-06-18 15:02:56 -03:00
Diego Rodrigues de Sa e Souza
75cf6baca4 feat(catalog): add kimi-k2.7-code to kmca catalog + qwen-web models discovery (#3931 bug 3, #3737) (#4185)
Integrated into release/v3.8.29 — add moonshotai/kimi-k2.7-code to the kmca (kimi-coding-apikey) catalog (KIMI_CODING_SHARED.models), requested in discussion #3737. On resync: the PR's qwen-web PROVIDER_MODELS_CONFIG addition (issue #3931 bug #3) was already shipped by #4172 — dropped the duplicate, kept release's entry (which has the Array.isArray guard); kept #4183's KIMI_K27_MODELS spread + added the moonshotai-prefixed entry (union). Also reconciled the file-size baseline for openai-to-gemini.ts (#4180 merged without its +20 bump). Validated: 13/13 tests (kmca catalog + qwen-web parse + kimi registration) + file-size green.
2026-06-18 14:36:50 -03:00
Hernan Javier Ardila Sanchez
d4e92db7a7 fix(provider-registry): add correct contextLength to theoldllm models (#4184)
Integrated into release/v3.8.29 — correct contextLength for theoldllm models. Adds an entry-level defaultContextLength (200000) + per-model overrides (GPT-5.4 400K, Gemini 3 Flash/Pro 1M, Claude/DeepSeek 200K) so the models report their real context windows instead of null. Thanks @herjarsa! On review we added a regression test (the resolved window was null before this fix), satisfying the PR Test Policy gate. 4/4 tests + eslint + prettier clean.
2026-06-18 14:28:12 -03:00
Raxxoor
89cd954322 fix(antigravity): default includeThoughts for modern Gemini models (#4180)
Integrated into release/v3.8.29 — default includeThoughts for modern Gemini (2.5+) in the openai->gemini translator, so the model's reasoning is marked thought:true and routed to reasoning_content instead of leaking into visible content (#4170). Thanks @dhaern! On review we regenerated the gemini golden snapshots (basic-chat/with-system) and committed the new modern-gemini-default-thinking snapshot. 61/61 translator + golden tests pass; eslint clean. Respects explicit client thinking config (only applies when none is set) and excludes gemini-1.x / non-thinking 2.0.
2026-06-18 14:16:59 -03:00
Diego Rodrigues de Sa e Souza
4537fbe67b feat(api): register Kimi K2.7 Code models (kimi-k2.7-code + -highspeed) (#4183)
Integrated into release/v3.8.29 — register Kimi K2.7 Code (kimi-k2.7-code + -highspeed). New KIMI_K27_MODELS in providers/shared.ts (262144 ctx, vision+reasoning, temperature/top_p stripped = fixed sampling), wired into kimi-coding, kimi-coding-apikey, moonshot and kimi. Validated: 6/6 unit tests (all 4 providers advertise it + context + reasoning + param stripping) + file-size; PR CI CLEAN. OAuth coding endpoint validated live on the test VPS.
2026-06-18 13:55:17 -03:00
Diego Rodrigues de Sa e Souza
50543c31f7 fix(sse): surface mid-stream Gemini errors instead of a truncated 200 (#4177) (#4182)
When an upstream Gemini SSE stream emitted partial content followed by a JSON
error object ({"error":{"code":503,...,"status":"UNAVAILABLE"}}) instead of a
candidates payload, the gemini→openai translator dropped it: the no-candidate
branch only handled promptFeedback and returned null otherwise, so the stream
ended with finish_reason "stop" and the client got HTTP 200 with a truncated
body — masking the failure and skipping combo fallback.

geminiToOpenAIResponse now detects an error object (optionally wrapped in
response), records it as state.upstreamError preserving the real status (503/
UNAVAILABLE, or 429 for RESOURCE_EXHAUSTED), and lets stream.ts error the stream
out via the existing onFailure/buildErrorBody/controller.error path — the same
mechanism the openai-responses translator already uses.

Closes #4177

Co-authored-by: hartmark <hartmark@users.noreply.github.com>
2026-06-18 13:17:46 -03:00
Diego Rodrigues de Sa e Souza
10ecda256b feat(mitm): TLS-terminating capture for TPROXY (decrypt 2/N) (#4179)
Integrated into release/v3.8.29 — TLS-terminating capture for TPROXY (decrypt 2/N). New src/mitm/tproxy/tlsCapture.ts: TLS-terminates the intercepted client with a per-SNI leaf from the dynamic CA (#4173), feeds plaintext to an internal http.Server, captures to the Traffic Inspector as source 'tproxy' (sanitizeHeaders + maskSecret), and forwards re-encrypted via an injected seam (realForward uses connectMarked for anti-loop, #4169). Secure-by-default: rejectUnauthorized defaults true; errors via sanitizeErrorMessage; bounded timeouts + closeAllConnections. CaptureSource enum + Zod widened with 'tproxy'. Validated: 17/17 unit tests (real local TLS round-trip + secret masking + 502/error path), targeted typecheck of changed files clean, file-size + test-discovery green.
2026-06-18 13:04:42 -03:00
Diego Rodrigues de Sa e Souza
798fce727c refactor(combo): god-file split part 2 — shadow + sorters + structure (QG v2 Fase 9 T5 D4-D6) (#4175)
Integrated into release/v3.8.29 — combo.ts god-file split part 2 (QG v2 Fase 9 T5 D4-D6): shadow routing, target sorters, and combo structure resolution extracted byte-identically to combo/{shadowRouting,targetSorters,comboStructure,comboData}.ts; combo.ts 4740->3819, public surface re-exported (callers unchanged). Validated on the rebased+merged tree: typecheck:core, file-size, test-discovery green; 356/356 full combo suite + 51/51 smoke pass. Resynced with current release (baseline union: combo-split entries + #4176 free-models entry; combo.ts=3819, rateLimitManager=1035).
2026-06-18 12:52:06 -03:00
Felipe Sartori
5ef6a46977 feat(dashboard): import only free models + free-model list controls (#4176)
Integrated into release/v3.8.29 — import-only-free-models connection option + free/paid list filters and free-first sort. Thanks @felipesartori! On review we relocated the 3 React-component tests from tests/unit/ to tests/unit/ui/ so a runner actually collects them (check:test-discovery had flagged them as orphans), bumped the file-size baseline for the two connection modals (cohesive toggle, mirroring #3879/#2997), and synced the branch with the current release. 12/12 vitest + 16/16 node tests green.
2026-06-18 12:19:54 -03:00
Diego Rodrigues de Sa e Souza
771f1cfac9 fix(build): raise Node heap for local next build to stop OOM/stall (#4171)
Integrated into release/v3.8.29 — raise Node heap for local next build (extends #4104 Docker OOM fix to the native path). Validated: 10/10 tests, typecheck:core, file-size, test-discovery, eslint green.
2026-06-18 11:23:12 -03:00
Diego Rodrigues de Sa e Souza
aaa740f7fd feat(mitm): dynamic per-SNI cert authority for TPROXY (TLS decrypt 1/N) (#4173)
Integrated into release/v3.8.29 — dynamic per-SNI cert authority (TLS decrypt 1/N). Validated: 5/5 tests, typecheck:core, file-size, test-discovery green.
2026-06-18 11:23:06 -03:00
Diego Rodrigues de Sa e Souza
f7880453e2 fix(providers): qwen-web model discovery lists live catalog (#3931) (#4172)
qwen-web (cookie provider) had no PROVIDER_MODELS_CONFIG entry, so its model-
discovery page returned an empty/stale local catalog — the OAuth fallback at the
top of the route only fires for provider===qwen, so qwen-web fell through to the
no-config branch.

Added a qwen-web entry that fetches the public https://chat.qwen.ai/api/v2/models
endpoint (no auth header configured/sent) and parses the
{ data: { data: [{ id, name, owned_by }] } } shape, with a flatter { data: [] }
fallback.

This is Problem #3 of #3931 (diagnosed by @thezukiru). Problem #1 (validator
bare-token false-positive) shipped earlier in the merged PR #3958; Problem #2
(empty stream from Qwen WAF bot-detection on the streaming endpoint) is a
separate upstream/stealth concern and stays open.

TDD: tests/unit/qwen-web-models-discovery-3931.test.ts mocks the upstream and
asserts source==='api' + the live ids (and the flatter shape), RED 0/2 ->
GREEN 2/2. Rebaselined route.ts 2512->2531.

Co-authored-by: thezukiru <thezukiru@users.noreply.github.com>
2026-06-18 11:16:44 -03:00
Dayna Blackwell
fa210de473 feat(compression): replace headroom tabular encoder with vendored GCF (#4167)
Integrated into release/v3.8.29. Thanks for the high-quality contribution!
2026-06-18 10:57:38 -03:00
Diego Rodrigues de Sa e Souza
a9e7e38d57 feat(mitm): TPROXY capture-mode listener + connectMarked (Epic A) (#4169)
Integrated into release/v3.8.29
2026-06-18 10:52:37 -03:00
Diego Rodrigues de Sa e Souza
0fc305e4f8 fix(api): advertise built-in auto/* combos in /v1/models (#4164) (#4170)
OmniRoute ships a zero-setup auto/* catalog (auto/best-coding, auto/pro-
reasoning, …, 16 AUTO_TEMPLATE_VARIANTS) that the dashboard advertises and that
resolve on demand via createBuiltinAutoCombo, but the /v1/models listing only
emitted persisted DB combos + provider models. Clients that build their model
picker from /v1/models (e.g. Hermes Agent) never saw any auto/* option.

The catalog now emits every AUTO_TEMPLATE_VARIANTS id (owned_by: combo) at the
top of the list, deduped against persisted combos so a user combo can't shadow
or double a built-in id.

TDD: tests/unit/models-catalog-auto-combos-4164.test.ts asserts every auto/*
variant is advertised, they sit at the top, and ids are unique (RED 2/3 ->
GREEN 3/3). Aligned the existing 'context_length for individual chat models'
test to exclude owned_by:combo entries (combos/routers resolve dynamically and
have no fixed context_length — they are not individual chat models).
2026-06-18 10:50:00 -03:00
Diego Rodrigues de Sa e Souza
1e4ce6cdab fix(sse): clear error when request queue drops a job, not fake-upstream timeout (#4165) (#4168)
Under concurrent load, requests exceeding the per-connection rate-limit queue
budget (resilienceSettings.requestQueue.maxWaitMs) are dropped by Bottleneck with
its raw 'This job timed out after <maxWaitMs> ms.' message. That string is
indistinguishable from an upstream gateway timeout, so the 502 body and call-log
last_error masquerade as a provider outage across unrelated providers (TI:0|TO:0)
— the #4165 reporter spent ~3h misdiagnosing local queue saturation as upstream
failures.

withRateLimit now rewrites that specific Bottleneck error into a clear,
OmniRoute-owned message: names the knob (requestQueue.maxWaitMs, Settings →
Resilience), disclaims an upstream timeout, preserves the original as cause, and
tags code=RATE_LIMIT_QUEUE_TIMEOUT. Behavior unchanged — the job is still dropped
so combo falls back.

TDD: tests/unit/rate-limit-queue-timeout-message-4165.test.ts drives a real
Bottleneck expiration (tiny maxWaitMs + a slow job) and asserts the surfaced
error carries the code + clear message and no longer leaks 'This job timed out'
(RED 1/2 -> GREEN 2/2). Rebaselined rateLimitManager.ts 1022->1035 at the
existing catch chokepoint.
2026-06-18 10:40:30 -03:00
Diego Rodrigues de Sa e Souza
305474de85 refactor(sse): split chatCore.ts pure helpers into chatCore/ modules (−561 LOC) (#4159)
Integrated into release/v3.8.29 (re-synced: kept only the chatCore split, dropped the stale-merge contamination)
2026-06-18 10:20:08 -03:00
Diego Rodrigues de Sa e Souza
0e33b2bfba refactor(combo): god-file split pilot — types + validateQuality + predicates (QG v2 Fase 9 T5 D1-D3) (#4162)
Integrated into release/v3.8.29
2026-06-18 10:11:33 -03:00
Diego Rodrigues de Sa e Souza
0283308147 feat(mitm): add setSocketMark to the TPROXY addon (anti-loop primitive) (#4160)
Integrated into release/v3.8.29
2026-06-18 10:11:29 -03:00
Diego Rodrigues de Sa e Souza
e0fe4facdf feat(dashboard): grid wallpaper on all standalone screens + fluid 4K layout (#4158)
Integrated into release/v3.8.29
2026-06-18 10:07:16 -03:00
Diego Rodrigues de Sa e Souza
a0e7e92e64 fix(capabilities): resolve synced vision metadata for Mistral -latest aliases (#4073) (#4161)
models.dev catalogs Pixtral 12B under the short id `pixtral-12b` (attachment:
true, image modality), while requests use the Mistral API alias
`pixtral-12b-latest`. getSyncedCapabilityForResolved tried only exact / raw /
static-spec-canonical ids, all of which miss the short form, so vision fell
through to the #4071 model-id heuristic and `attachment` stayed null.

Add a last-resort fallback that retries the synced lookup with a trailing
`-latest` stripped, so synced metadata wins for these aliases. Models whose
`-latest` id is stored verbatim (e.g. pixtral-large-latest) keep resolving
directly. TDD: tests/unit/model-capabilities-mistral-vision-sync-4073.test.ts
(RED 2/4 -> GREEN 4/4) seeds a synced fixture and asserts the verdict comes via
the synced path (attachment === true/false), not the heuristic.

The models.dev sync remains manual-only (no scheduled refresh) — documented as a
separate follow-up.
2026-06-18 05:00:52 -03:00
Diego Rodrigues de Sa e Souza
46c76103da fix(mitm): TPROXY OUTPUT-based recipe for local traffic (validated e2e on VPS) (#4156)
Integrated into release/v3.8.29
2026-06-18 04:34:51 -03:00
Diego Rodrigues de Sa e Souza
9aae6b9158 fix(capabilities): unify vision model-id detection into one shared source (#4072) (#4157)
Integrated into release/v3.8.29
2026-06-18 04:34:48 -03:00
Diego Rodrigues de Sa e Souza
5c0c97461e fix(dashboard): self-heal logs auto-refresh in embedded/proxied hosts (#4133) (#4154)
Follow-up to #4054. The Request Logger still froze auto-refresh on some hosts
(reported on 3.8.28 Docker, works on 3.8.24). #4054 made the INITIAL visibility
fail-open, but the pause is event-driven: a host that fires a one-shot
visibilitychange->hidden and then keeps reporting 'hidden' (or recovers without
firing the event again) left visibleRef stuck false, so the interval ticked but
never polled - only the manual Refresh button worked.

The poll tick now also re-checks the LIVE document.visibilityState, and a window
'focus' listener re-arms polling (a focused window is a reliable signal the page
is actively viewed). A genuinely backgrounded browser tab still pauses (reports
'hidden' and never receives focus), preserving the #3109 optimization.

TDD: two new jsdom regression tests (RED on current release, GREEN after);
the existing 'pause on real background' test stays green.
2026-06-18 04:02:40 -03:00