mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-02 13:22:11 +03:00
b710f1a7e342cbd32060915bcfd040faea5753c7
2098 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b710f1a7e3 |
fix(mitm): mask bare "Bearer <token>" header values in the inspector (#4358)
sanitizeHeaders() masks header *values* — it calls maskSecret("Bearer
<token>") with the "authorization:" key already stripped. The BEARER regex
was anchored to a literal "authorization:" prefix, so it never fired on those
values; tokens shorter than the sk-(16+)/opaque-(40+) thresholds then leaked
verbatim into the Traffic Inspector buffer (Hard Rule #12).
Found by the AgentBridge live capture: a 'Bearer sk-secret-TESTE' request
header showed up unmasked in /api/tools/traffic-inspector/requests. Real Google
OAuth tokens are long enough to be caught by LONG_TOKEN, but the Bearer pattern
must mask regardless of length.
Re-anchor BEARER to a standalone \bBearer\s+<token> (still ReDoS-safe:
bounded char class, no nested quantifiers). Masks both bare 'Bearer <token>'
header values and 'authorization: Bearer <token>' raw lines; existing cases
(sk-/ak-/pk- keys, short keys, no-secret strings) unchanged.
Tests: bare Bearer value, short opaque Bearer, realistic Google OAuth Bearer,
plus an authorization:-prefixed regression.
|
||
|
|
4038e4de4a |
fix(pricing): price gpt-5.x-pro openai models + align opencode-go discovery test (#4355)
* fix(pricing+test): price gpt-5.x-pro openai models + align opencode-go discovery test
Two pre-existing reds on the release's full unit suite (only surface under __RUN_ALL__):
1. catalog-updates-v3x: the provider sweep added gpt-5.5-pro / gpt-5.4-pro to the
openai registry but no pricing rows, so they resolved to $0 and tripped the
'Every OpenAI registry model resolves a non-zero pricing row' gate. Add both
under the openai pricing block (mirroring their base family tier until OpenAI
publishes a distinct pro rate).
2. provider-models-route: opencode-go discovery now (a) stamps owned_by on each
discovered model (fallback = provider id) and (b) probes ${base}/v1/models then
${base}/models (T39 multi-endpoint). The test fixtures predated both — add
owned_by to the expected model and bump the fail-path fetchCalls 1 -> 2. Test-only
alignment to the intentional route behavior.
* chore(quality): rebaseline file-size for #4355 (pricing +11, route test +2)
|
||
|
|
7a7b437b61 |
fix(quality): restore release/v3.8.30 green — 3 latent reds from concurrent merges (#4335)
* fix(providers): bailian-coding-plan static catalog matches registry (10 models) The provider-model sweep (#4324) added qwen3.7-plus, qwen3-coder-plus, qwen3-coder-next and glm-4.7 to the bailian-coding-plan registry entry but left the static fallback mirror in staticModels.ts at the older six, so the static↔registry parity test (bailian-coding-plan-provider.test.ts) went red on release/v3.8.30 whenever TIA selected it. Restore the mirror to all ten models in registry order and align the two legacy count/ID assertions. * chore(test): collect tests/unit/combo/ in the unit runner glob PR #4326 (ComboContext god-file split) added tests/unit/combo/combo-context.test.ts but the unit-runner brace glob had no 'combo' entry, so its 4 tests were orphaned — check:test-discovery flagged a NEW orphan, a second latent red on release/v3.8.30. Add 'combo' to the glob across all lock-step collectors: the 7 package.json test scripts, build-test-impact-map.mjs, check-test-discovery.mjs and the 4 ci.yml run lines. Folded here (rather than a separate PR) because the two release reds are interdependent for Fast-QG: a package.json change triggers the full suite, so a combo-only PR would still trip the bailian red and vice-versa — fixing both in one PR is the only way to land a genuinely green Fast-QG. * chore(db): register apiKeyColumnFallbacks + apiKeyUsageLimitFields as db-internal The api-key usage-limits feature (migration 101) split two helper modules out of src/lib/db/apiKeys.ts — apiKeyColumnFallbacks.ts and apiKeyUsageLimitFields.ts — but did not register them with check:db-rules, so both were flagged as new db/ modules not re-exported by localDb.ts (Hard Rule #2), a third latent red on release/v3.8.30. Both are imported only by db/apiKeys.ts (within src/lib/db/), so they are db-internal: add them to INTENTIONALLY_INTERNAL with that classification (mirrors healthCheck / stateReset) rather than re-exporting internal helpers onto the public localDb surface. |
||
|
|
70d89d2f68 |
feat(keys): add per-key USD usage quota controls (#4327)
* feat(keys): add per-key USD usage quotas Adds daily and weekly API key USD caps with reset-aware weekly windows, exposes quota controls in API key permissions and costs views, and returns Claude Code-safe 400 responses when caps are exceeded. Validations: - node --import tsx/esm --test tests/unit/api-key-usage-limits.test.ts tests/unit/internal-usage-command.test.ts - npm run typecheck:core - npm run check:file-size - npm run check:migration-numbering - npm run lint - Docker image build/deploy smoke test on 100.64.0.1:20128 * fix(db): renumber api_key_usage_limits migration 100->101 (avoid cli_access_tokens collision) Migration version 100 is taken by 100_cli_access_tokens.sql on release; the migrationRunner version-collision guard would otherwise skip one. Renumber to 101. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> * chore(quality): bump apiKeys.ts file-size baseline 1661->1662 (USD quota fields) Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> --------- Co-authored-by: Wital <wital@example.com> Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
5cca4ff90c |
fix(executors): reconstruct LMArena split auth cookie (#4271) (#4331)
LMArena migrated to @supabase/ssr chunked auth cookies: the single arena-auth-prod-v1 cookie is now empty and the session is split across arena-auth-prod-v1.0, .1, … (ascending). Pasting the now-empty single cookie sent an empty session, which upstream rejected as "invalid cookie". reconstructLMArenaCookie() rebuilds the single cookie from its chunks (ascending join, no decode/parse — combineChunks semantics), preserving the rest of the pasted jar; a non-empty single cookie is forwarded unchanged (back-compat). The credential UX now instructs pasting the full Cookie header and tracks the .0/.1 storage keys. Closes #4271 |
||
|
|
8f21fcee99 |
fix(security): bound prompt-injection regex scan to first 16KB (#3932) (#4332)
The prompt-injection guard joined every message/system string into one buffer and ran several regexes over the whole thing on every chat request, with no size cap. At high concurrency with large bodies (300 KB of pasted code / RAG context) that is O(body) CPU scanning on the hot path — a self-inflicted latency/GC source under load. Bound both detection call sites — detectInjection() in inputSanitizer.ts and the custom-pattern scan in promptInjection.ts — to the first 16 KB via a named MAX_INJECTION_SCAN_BYTES constant, slicing the joined text before the regex loop. Injection directives sit near the top of a prompt, so the generous cap preserves real detection while scanning only a bounded prefix. No call site removed and opt-out behavior unchanged; this only bounds the scan length. The existing 10 MB body-size cap that protects ingestion is separate and untouched. TDD: tests/unit/injection-guard-scan-bound-3932.test.ts proves a directive at the top of a >16 KB body is still detected (case 1) while the same marker placed beyond the 16 KB cap is no longer scanned (case 2, RED before the fix), at both call sites. Refs #3932 |
||
|
|
5d89fa84e7 |
fix(compression): end-to-end audit — fixes across the whole compression flow (#4323)
* fix(compression): SLM worker resolves deps+worker file without import.meta.url (B-SLM) The Next.js standalone bundle (webpack) replaces createRequire(import.meta.url) with a stub that always throws MODULE_NOT_FOUND, and freezes import.meta.url to the build-machine path. So depsAvailable() was always false (the worker never spawned) and resolveWorkerFile() anchored on a path absent at runtime — the SLM silently fell back to the aggressive summarizer in production. Confirmed by inspecting dist/.build/next/server/chunks/26410.js (stub module 215743 + frozen file:// path). Replace both with filesystem probing from runtime anchors (process.cwd(), process.argv[1]) that survive the bundle. Necessary complement to #4286 (deps co-location) for the SLM to actually engage in prod; still fail-open without it. VPS live validation deferred (Rule #18); local resolver regression tests added. * fix(compression): ultra heuristic preserves code blocks / inline code / URLs (B-ULTRA-CODE) ultra.ts called pruneByScore on raw text with no tombstoning, so the token pruner dropped low-score code tokens (`b)`, `{`, `+`) inside fenced blocks while leaving the fence markers intact — output that looked like valid code but was syntactically destroyed. caveman + llmlingua both extract/restore preserved blocks first; ultra was the only pruning engine that didn't. Add pruneProseOnly(): extractPreservedBlocks tombstones fenced code, inline code, URLs, CONST_CASE, versions; only the prose between placeholders is pruned; preserved blocks are re-stitched verbatim. * fix(compression): GCF round-trips values containing the inline-array pattern [..]: (B-GCF-QUOTE) A value like `ERR[404]: Not Found` / `[Speaker 1]: Hello` nested one level deep was emitted bare and re-parsed by the decoder as an inline-array header → it threw `count_mismatch` (or silently decoded wrong), losing the whole block. headroomEngine .apply() ships such blobs in prod, so this was a reachable lossless violation. Two complementary fixes, both per SPEC §2.4: - encode: needsQuote() now quotes strings matching `[`…`]``:` (spec compliance / other decoders). - decode: the inline-array branch only fires when the bracket is in the KEY position (no `=` before it), so a quoted `note="ERR[404]: …"` value falls through to key=value. * fix(compression): aggressive fidelity — keep text blocks, compress Anthropic tool_result, don't corrupt JSON (B-AGG-*) Three fidelity fixes in the aggressive path (each TDD, aggressive-fidelity.test.ts): - B-AGG-TEXTDROP: replaceTextContent dropped 2nd+ text blocks unconditionally; now a trailing block is dropped only when its text is already subsumed by newText, else kept. - B-AGG-ANTHROPIC-TR: tool-result compression only fired for OpenAI role:tool messages; now Anthropic-shape tool_result content blocks (inside user messages) are compressed too, preserving tool_use_id + block structure. - B-AGG-JSONTAG: the [COMPRESSED:aging:*] prefix corrupted JSON/code payloads; pure JSON is now kept verbatim+untagged (stays parseable), fenced blocks get the tag on a preceding line. * fix(compression): accessibility collapse preserves [ref] anchors + fires on interleaved trees (B-MCPA11Y-*) - B-MCPA11Y-ANCHORS: collapseRepeated silently dropped the omitted middle siblings' [ref=eNN] anchors (the agent could no longer click them); now every omitted ref is kept alongside the collapse notice. Wires the previously-dead preserveRefPattern. Invariant: extractRefs(input) ⊆ extractRefs(output). - B-MCPA11Y-COLLAPSE: noise removal blanked lines (replace→""), and a blank line broke the sibling run so collapse never fired on realistic interleaved trees; noise lines are now deleted, and the sibling walk skips stray blanks. * fix(compression): rtk intensity scales the line budget (B-RTK-INTENSITY) The intensity knob only set smartTruncate's preserveHead/Tail (16↔24), which rarely fired because the matched filter capped lines first — so minimal/standard/aggressive produced byte-identical output on filter-matched tool output. effectiveMaxLines() now scales the effective line budget (minimal 1.5x, standard 1x, aggressive 0.5x) at both the per-filter and engine-level truncation sites. Both go through smartTruncate with priorityPatterns, so error/failure lines survive at every intensity (tested). * fix(compression): robust language detection + auto-detect honors the detected pack (B-LANG-*) - B-LANG-DETECTOR: detector was first-match-wins on a single keyword, and some hints are English-ambiguous ("configuration" in fr, "error" in es) → English text misclassified. Now score-based (count native-keyword hits, highest wins), and the two English-ambiguous words are removed from the hint lists, so a lone shared word never misclassifies while sparse-keyword languages (id) still detect on a single native word. - B-LANG-DORMANT: with autoDetectLanguage on but enabledPacks ["en"], detected non-English text fell back to the English pack, whose `articles` rule deletes foreign articles (pt-BR "a"/"o"). Auto-detect now uses the detected pack directly (it always has rules); enabledPacks still gates manual selection. * fix(compression): mode selection enables its engine + align stacked allowlist (B-MODE-ENGINE-DECOUPLE, B-PIPELINE-DIVERGENCE) - B-MODE-ENGINE-DECOUPLE: picking the standard/rtk MODE now runs caveman/rtk regardless of the per-engine enabled flag — the mode selection is the enable signal (the per-engine flag still gates stacked pipeline steps). Previously an operator who picked a mode but left the engine toggle off got silent 0% compression. - B-PIPELINE-DIVERGENCE: the global stackedPipeline normalizer stripped session-dedup/ccr/headroom/llmlingua (engines the combo path accepts via KNOWN_ENGINE_IDS). The allowlist now matches, so the global setting can use all registered engines. * docs(compression): correct SLM "stable" claim + document partial packs / stacked telemetry limits - The llmlingua `stable:true` comment claimed the bundle walk-up + deps-gate were "confirmed against the live install" — that was wrong (webpack froze import.meta.url and stubbed createRequire, so the worker never spawned in prod). Corrected to reflect B-SLM. - COMPRESSION_ENGINES.md: add a Known limitations section (SLM dep co-location requirement, partial de/fr/ja packs, no-op engines absent from engineBreakdown). * fix(compression): cast normalized engine id to CompressionPipelineStep['engine'] (typecheck) |
||
|
|
2c0fd04704 |
feat: implement 5 harvested feature requests (#4239, #4155, #3841, #3266, #4240) (#4313)
* feat(providers): add OpenAdapter, dit.ai and TokenRouter OpenAI-compatible providers (#4239, #4155, #3841) Three community-requested OpenAI-compatible aggregators register as standard named OpenAI-style providers (the zenmux pattern): live /v1/models discovery via NAMED_OPENAI_STYLE_PROVIDERS, falling back to a seeded catalog on upstream error. No custom executor/translator — default OpenAI passthrough. - OpenAdapter https://api.openadapter.in/v1 (free tier) #4239 - dit.ai https://api.dit.ai/v1 (dynamic-pricing) #4155 - TokenRouter https://api.tokenrouter.com/v1 (free MiniMax model) #3841 Base paths confirmed live (each returns a 401 OpenAI-style error body). Seed catalogs are intentionally minimal (author/doc-cited ids only; TokenRouter deepseek ids come from production via #3946); full upstream model lists arrive through live discovery once a key is configured. * feat(combo): per-step account allowlist for round-robin over a connection subset (#3266) A combo model step can now carry a first-class `allowedConnectionIds` so a round-robin / weighted strategy is scoped to a subset of a provider's connections (e.g. {foo1, foo2}) without hand-pinning one step per account. - steps.ts: parse `allowedConnectionIds` on the model step (trim + drop empty) - comboStructure.ts: second writer — propagate the step allowlist onto the resolved target (tag routing is the first writer) - autoStrategy.ts: when a step allowlist AND tag routing both apply, intersect them (most-restrictive wins); empty intersection drops the target - builderDraft.ts + combos UI: optional 'Restrict to accounts' picker in the Precision step editor (a pinned single account still takes precedence) The downstream credential-selection filter (auth.ts) already honours allowedConnectionIds, so a round-robin scoped to {foo1, foo2} provably never selects foo3/foo4 (regression test included). Ships the enhancement only; the #2829 bug-triage half stays open pending the reporter. * feat(dashboard): category (media serviceKind) filter on the providers page (#4240) Add a media-category filter row (Image / Video / Music / Text→Speech / Speech→Text / Embedding) to /dashboard/providers that composes with the existing search, free-only and 'show configured only' filters. - serviceKindIndex.ts: client-side resolver unioning a provider's declared serviceKinds with the registry-derived media kinds (memoised) - providerPageUtils: filterConfiguredProviderEntries gains a serviceKindFilter argument; threaded through every provider section on the page - ProviderSummaryCard: a second chip row drives the serviceKind filter Membership is derived from the backend media registries, so a provider that serves a kind is surfaced even when it never declared serviceKinds — keeping the UI in lockstep with the backend (mirrors the media-providers pages). * chore(quality): rebaseline file-size for the v3.8.30 harvested features Four frozen files grew from their own additive feature wiring (#4239/#4155/#3841 providers, #3266 combo allowlist UI, #4240 serviceKind filter): - src/shared/constants/providers.ts 3169->3213 (3 provider entries) - src/app/api/providers/[id]/models/route.ts 2554->2560 (3 NAMED set entries) - src/app/(dashboard)/dashboard/combos/page.tsx 4350->4385 (allowlist picker) - src/app/(dashboard)/dashboard/providers/page.tsx 1925->1927 (serviceKind state) All cohesive additive wiring at existing chokepoints; rationale recorded in the _rebaseline_2026_06_19_v3830_harvest_features key. |
||
|
|
7ce875f404 |
feat(providers): provider model sweep — live discovery, refreshed catalogs, dead-provider cleanup (#4324)
* feat(providers): refresh core official model catalogs (sweep lote 1) Adiciona modelos GA atuais (verificados online) aos provedores oficiais core: - openai: gpt-5.5-pro, gpt-5.4-pro - anthropic: claude-opus-4.8 + claude-fable-5 (sampling fixo 4.7+, espelha 4.7), claude-opus-4.5 - groq: qwen/qwen3.6-27b, openai/gpt-oss-safeguard-20b - xai: grok-build-0.1 Fase 4 do provider-model-sweep. provider-consistency/file-size/typecheck:core verdes. * feat(providers): wire live /models discovery for 7 openai-style providers (sweep lote 2) venice, deepinfra, wandb, pollinations, nscale, inference-net and moonshot each expose a real live `<baseUrl>/models` catalog (the sweep probed each upstream), but were classified fixed-official, so import served their small hardcoded seed and re-staled the catalog. Add them to NAMED_OPENAI_STYLE_PROVIDERS so import does a live `<baseUrl>/models` fetch, keeping the registry seed only as the offline fallback — same fix shape as #4249 (vercel-ai-gateway) / #4202 (zenmux) / #3976 (llm7/byteplus). siliconflow was already classified. TDD regression in tests/unit/provider-sweep-live-discovery.test.ts pins each derived /models URL + the local-seed fallback path. file-size baseline bumped 2538->2548 (+10 = 7 Set entries + 3-line comment; not extractable). * feat(providers): wire live /models discovery for 12 aggregator marketplaces (sweep lote 3) crof, featherless-ai, ovhcloud, sambanova, orcarouter, uncloseai, opencode-go, baseten, hyperbolic, nebius, scaleway and together are GPU-cloud / aggregator marketplaces hosting large, volatile OSS catalogs. The sweep probed each and confirmed a live `<baseUrl>/v1/models` endpoint (200 public or 401/403 = exists + keyed), yet they were classified fixed-official and served a small hardcoded seed. Add them to NAMED_OPENAI_STYLE_PROVIDERS so import does a live `<baseUrl>/models` fetch (graceful fallback to the registry seed on any upstream error), keeping the catalog fresh instead of re-staling a hardcoded list. Extends tests/unit/provider-sweep-live-discovery.test.ts to 20 cases pinning each derived /models URL. file-size baseline bumped 2548->2564 (+16; not extractable). * feat(providers): add verified new models to nvidia, meta-llama, morph (sweep lote 4) Curated first-party / specialist menus (kept hardcoded — their per-model flags like toolCalling/supportsReasoning can't be inferred from a live catalog): - nvidia: + stepfun-ai/step-3.7-flash, deepseek-ai/deepseek-v4-flash (supportsReasoning), moonshotai/kimi-k2.6 — all confirmed present in the live NIM /v1/models catalog. minimaxai/minimax-m3 deliberately left out per #3329 (now listed, but its inference still needs confirmation before re-adding). - meta-llama: + Llama-3.3-8B-Instruct. - morph: + morph-qwen35-397b, morph-minimax27-230b, morph-qwen36-27b, morph-dsv4flash (Morph-hosted fast models, with context lengths). Skipped this batch after review: upstage solar-pro2 (older than the solar-pro3 already in the registry); longcat LongCat-2.0-Preview (deliberately commented out). * feat(providers): refresh Chinese first-party model catalogs, online-verified (sweep lote 5) Each registry held a single stale id; refreshed against official docs after per-id online verification (subagent research, cross-checked against first-party sources). Rejected/omitted entries are documented inline. - baidu: + 15 ERNIE ids (5.0/5.1 are the current flagships, confirmed live on Qianfan). - doubao: + 8 Seed-2.0/1.x dated Ark ids (Seed 2.0 GA 2026-02-14, confirmed real). - sensenova: + 8 SenseChat/SenseNova ids (V6.5-Pro flagship; 6.7-flash-lite lowercase). - tencent: + hunyuan-turbos-latest/t1-latest/vision/functioncall/lite. Dropped legacy standard/-256K/code/role + pinned turbos-20250226. NOTE: legacy Hunyuan platform EOLs turbos/t1 on 2026-06-22 (migrating to TokenHub/hy3-preview) — revisit. - baichuan: + Baichuan4-Turbo/Air, Baichuan3-Turbo/-128k (official pricing page). - stepfun: + step-3.7-flash (flagship), step-3.5-flash(-2603), step-1o-turbo-vision. - iflytek: + 4.0Ultra, max-32k, generalv3, pro-128k, lite (exact HTTP domains). - sparkdesk: + 4.0Ultra, generalv3, pro-128k. Rejected spark-x (separate /v2|/x2 endpoint). - volcengine: + doubao-seed-2-0-pro-260215, kimi-k2-5-260127 (Ark-hosted). * feat(providers): add verified models to kie, nlpcloud, publicai (sweep lote 6) - kie: + claude-opus-4-8, gemini-3-5-flash (current flagships the proxy surfaces; gemini-3-pro skipped — registry already carries the newer gemini-3-1-pro). - nlpcloud: + chatdolphin, dolphin (branded models), finetuned-llama-3-70b, llama-3-1-405b. Host confirmed reachable. - publicai: + Apertus-8B, Gemma-SEA-LION-v4-27B, Olmo-3-7B, EuroLLM-22B (open models). Skipped after review: minimax M2/M2.1 (older than the M2.5 floor the registry curates); yi (api.lingyiwanwu.com degraded + 01.AI exited foundation models); llamagate (host llamagate.ai unreachable, code 000) — both flagged for Track C. * feat(providers): finish Track B tail — cloudflare-ai, bailian, suno, +5 (sweep lote 7) - cloudflare-ai: + 7 Workers AI catalog ids (llama-3.3-70b-fp8-fast, qwen2.5-coder-32b, qwq-32b, llama-3.2-3b, glm-4.7-flash, kimi-k2.6, gemma-4-26b). - bailian-coding-plan: + qwen3.7-plus, qwen3-coder-plus, qwen3-coder-next, glm-4.7. - suno: + chirp-fenix (V5.5), chirp-crow (V5). - monsterapi: + Meta-Llama-3.1-8B, Llama-3.3-70B. - huggingchat: + Qwen3-235B-A22B, Mistral-Small-3.1-24B. - vertex-partner: + claude-opus-4-8, claude-opus-4-6. - puter: + google/gemini-3.5-flash. - codestral: + codestral-2508. Skipped after verification: windsurf + devin-cli — docs.devin.ai exposes DASHED ids (claude-opus-4-8-low, MODEL_PRIVATE_4 for "Grok Code Fast 1", minimax-m2-5) while the registry uses DOTTED (claude-opus-4.7-max); id-form ambiguity needs owner confirmation before adding 13+ entries. leonardo/ideogram (image UUID-vs-friendly convention), glmt (shared GLM_SHARED_MODELS, redundant with the live `glm` provider). * fix(providers): drop retired models, add codestral-2405 forward (sweep lote 8, Track C C1) Confirmed removals that interacted with the sweep's adds: - codestral: drop codestral-2405 (retired 2025-06-16, Mistral official docs) from the menu + add a codestral-2405 -> codestral-2508 deprecation alias so old configs forward. - monsterapi: drop llama-3-8b-fuse (no longer evidenced in the catalog). - volcengine: drop kimi-k2-thinking-251104 (retired on Ark; superseded by kimi-k2-5-260127). * chore(providers): mark 6 dead providers deprecated (sweep lote 9, Track C C2) The sweep verified these providers are no longer reachable/operational, so flag them with the existing deprecation mechanism (deprecated:true + a deprecation risk notice) instead of silently offering non-working options. Conservative — plumbing (executors/icons/free-catalogs) is left intact; only the UI-facing metadata changes. - kluster, glhf, predibase, inclusionai, galadriel: api host DNS no longer resolves. - phind: API shut down 2026-01 (www.phind.com/api/chat no longer serves). Not touched: gemini-cli (Google OAuth infra still live), qwen (already deprecated), chipotle (easter-egg, out of scope). file-size baseline bumped 3169->3198. * fix(providers): replace retired LongCat-Flash line with LongCat-2.0-Preview (sweep lote 10) The LongCat-Flash-* models (Lite/Chat/Thinking/Omni-2603) were officially retired 2026-05-29; the current longcat.chat/platform docs expose only LongCat-2.0-Preview (confirmed via WebFetch of the live API docs). Swap the stale 4-model seed for the single current model so the provider stops offering dead ids. * chore(quality): reconcile antigravity.ts file-size baseline 1664->1680 #4309 (Undici socket-leak fix) grew antigravity.ts by +26 lines but its file-size baseline was not bumped at merge time; reconcile it here on the combined tree so the release file-size gate stays green (Rule #9, release-volatile reconciliation). |
||
|
|
0d6c5686d2 |
feat(dashboard): list MITM hosts-file entries in the tool card (#4325)
The CLI-tools MITM card's "How it works" section showed a single hardcoded example domain (only antigravity/kiro). It now lists every 127.0.0.1 <host> entry for the selected tool, so users on locked-down machines — where the automatic, sudo-gated hosts-file edit isn't available — can add them manually. Hosts come from a client-safe projection of the canonical src/mitm/targets registry (MITM_TOOL_HOSTS), kept in lock-step with the registry by a sync test (no duplicated source of truth). Co-authored-by: mrcyclo <13806369+mrcyclo@users.noreply.github.com> |
||
|
|
5193a595bf |
fix(dashboard): proxy modal stops pre-filling new scopes with an unrelated proxy (#4312)
The proxy assignments list returned by /api/settings/proxies/assignments is global, so its first entry belongs to some other scope. ProxyConfigModal picked `items.find(matchingScope) || items[0]`, so opening the proxy config for a freshly created provider/key (which has no assignment of its own) fell back to items[0] and pre-filled host/port/user/password from an unrelated proxy plus set hasOwnProxy=true — users reported a new provider already carried a proxy they never configured. Extracted the scope helpers into proxyAssignment.ts and added selectScopeAssignment which returns null (never items[0]) when the current scope has no assignment. The modal then shows the empty/custom state for new scopes. Both call sites now use it. TDD: src/shared/components/proxyAssignment.test.tsx (no-match -> null red->green for provider/key/global scopes; matching-scope + empty-list regression guards). Existing ProxyConfigModal component test stays green. |
||
|
|
db7c8c5edc |
fix(pollinations): handle auth-required premium models (#4266)
Pollinations now requires API keys for premium models (claude, gemini, midijourney). The executor surfaces an actionable 401 with the keyless-model list, chatCore preserves the upstream HTTP status (401 -> authentication_error instead of 502), and the free catalog marks the premium models as key-required. Rebased onto the release tip and reconciled the file-size baseline (chatCore 5128). Thanks @oyi77. |
||
|
|
a23d0d678a |
fix(api): semantic-cache HIT bills incremental cost 0 + X-OmniRoute-Cost-Saved (PRD-2026-06-19) (#4308)
Cache HITs now report Response-Cost 0 (incremental) and surface the avoided cost in X-OmniRoute-Cost-Saved. MISS path unchanged. TDD + per-key isolation guard. |
||
|
|
0ab1876008 |
feat(mitm): translate Antigravity cloudcode end-to-end (Gap B) (#4299)
The Antigravity IDE speaks cloudcode (the Gemini payload wrapped under
`request`) and expects a cloudcode reply ({response:{candidates}}). The
AgentBridge proxy forwarded that envelope verbatim to /v1/chat/completions
(OpenAI), which 400s on the missing `messages` field — so the IDE could be
decrypted/intercepted but never actually routed to a provider.
Wire the inbound cloudcode path, reusing the already-registered bidirectional
translators (no new translators needed):
- provider.ts: detectFormatFromEndpoint classifies the /antigravity path as
sourceFormat "antigravity" (mirrors /messages -> claude), so the pipeline
translates request antigravity->openai and response openai->antigravity.
- /v1/antigravity route (new): cloudcode-compatible endpoint — just calls
handleChat (mirrors /v1/messages).
- server.cjs: routes cloudcode envelopes to /v1/antigravity (translates both
ways) and plain OpenAI bodies to /v1/chat/completions, via a testable shim.
Tests: forward-target shim (cloudcode vs openai routing) + endpoint format
detection. The antigravity<->openai translators are already covered by
translator-antigravity-to-openai / translator-resp-openai-to-antigravity.
Stacked on #4285 (Gap A). Full Antigravity-IDE e2e validates on the next
standalone deploy (provider.ts + the route compile into .next).
|
||
|
|
915991c762 |
fix(codex): isolate Spark quota scope (#4293)
* fix(codex): isolate Spark quota scope * fix(codex): address Spark quota review feedback * fix(ci): update Electron undici override * fix(ci): update root undici overrides * test(integration): sync stale expectations * test(tproxy): tolerate available native addon * test(tproxy): avoid environment-specific skips * test(tproxy): keep assertion count stable * fix(ci): stabilize quality and tproxy checks * chore(ci): rebaseline auth file size * fix(ci): extend node compatibility budget * chore(quality): reconcile complexity + file-size baselines after release/v3.8.30 merge (#4293) Measured on the actual merged tree (not the PR's main-based estimate): complexity 1885->1887 (+2); file-size auth.ts 2219->2279, chatCore.ts 5116->5125, accountFallback.ts 1727->1731, + the 4 Codex test files. Drift test-file conflicts (search-providers-catalog, tproxy-transparent-socket, integration-wiring) resolved to the already-merged release versions (#4276). Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> --------- Co-authored-by: ci <ci@local> Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
b01b72052f |
fix(dashboard): improve API try it functionality (#4296)
* fix(dashboard): improve api try it functionality and allow manual key entry * test(api): cover generateExampleFromSchema for the Try It panel (#4296) Export generateExampleFromSchema from the /api/openapi/spec route and add a unit test covering type handling, property-name heuristics, $ref/oneOf/anyOf/ allOf resolution, the 'required + first 3 optional' object policy, and the depth-3 recursion guard — the example bodies the dashboard Try It panel pre-fills. Rule #18 regression guard for the new helper. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> --------- Co-authored-by: ci <ci@local> Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
b56b7b1914 |
fix: polyfill crypto.randomUUID for non-secure contexts (#4287)
* fix: polyfill crypto.randomUUID for non-secure contexts crypto.randomUUID() requires a secure context (HTTPS or localhost). When accessing the dashboard over HTTP on a LAN IP, the function is undefined, causing 'Failed to add account' errors on providers that generate account IDs client-side (e.g. mimocode). Adds a lightweight polyfill that falls back to a Math.random()-based UUID v4 generator when the native API is unavailable. * fix: address review comments on crypto.randomUUID polyfill - Use crypto.getRandomValues() for cryptographic security instead of Math.random() - Add typeof window !== 'undefined' guard to avoid ReferenceError in non-browser envs - Use window.crypto for safe access instead of bare crypto reference - Replace var with const and == with === for modern JS syntax - Add fallback to Math.random() when getRandomValues is unavailable - Add unit tests verifying valid UUID v4 format, version/variant nibbles, uniqueness, and preference for getRandomValues over Math.random * test(dashboard): regression guard for crypto.randomUUID polyfill (#4287) Reads src/app/layout.tsx and asserts the blocking inline script installs a guarded window.crypto.randomUUID polyfill (RFC4122 v4 shape, getRandomValues preferred with a Math.random fallback). Fails on the pre-fix tree (no polyfill), passes with the fix — Rule #18 regression guard for the non-secure-context (HTTP/LAN-IP) dashboard breakage. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> --------- Co-authored-by: pizzav-xyz <pizzav-xyz@users.noreply.github.com> Co-authored-by: ci <ci@local> Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
efbe0a6af1 |
fix(mitm): surface AgentBridge traffic in the Traffic Inspector (D4 ingest) (#4285)
The standalone server.cjs proxy intercepts AgentBridge requests inline (no MitmHandlerBase / agentBridgeHook), so intercepted traffic never reached the TS hook that pushes into globalTrafficBuffer — the Traffic Inspector stayed empty for AgentBridge even on successful intercepts. Three gaps closed: - _internal/ingest.cjs (new): pure payload builder + fire-and-forget poster (never throws — capture must not break proxy traffic). - server.cjs: intercept() accumulates response (bounded) + status/headers and posts the captured entry to the local-only /internal/ingest endpoint in a finally block; also captures error/4xx intercepts. - manager.ts: resolves the ingest token via getIngestTokenForBootstrap() and passes it to the spawned proxy so the endpoint accepts the post. - authz management policy: exempt the loopback /internal/ingest endpoint from management auth — it has its own shared-secret token gate, and server.cjs has no dashboard cookie. Stays strictly loopback (LOCAL_ONLY gate unchanged). - ingest route: masks secrets / strips hop-by-hop headers before buffering (server.cjs sends raw over the token-gated loopback) — Hard Rule #12. Tests: ingest shim (build/post/no-token/error) + route sanitization + 403 + management-policy carve-out (loopback allow / remote LOCAL_ONLY). |
||
|
|
bf5b615969 |
feat(memory): x-omniroute-no-memory opt-out + memory off-by-default + token-cost alert (PRD-2026-06-19) (#4290)
* feat(memory): x-omniroute-no-memory opt-out + memory off-by-default + token-cost UI alert PRD-2026-06-19-no-memory-header. The gateway injects up to memorySettings.maxTokens (~2k) of memory (and skills) context into every chat call for memory-enabled keys, inflating tokens+cost ~137x for clients that manage their own context (e.g. Omniflow). Three changes: - A) x-omniroute-no-memory request header (mirrors x-omniroute-no-cache): when truthy (true/1/yes), skip memory+skills injection for that request. New pure helper isNoMemoryRequested() in chatCore/headers.ts; chatCore passes memoryOwnerId=null on opt-out (a null owner disables both injection branches). - B) Memory OFF by default: DEFAULT_MEMORY_SETTINGS.enabled true->false. Enabling injects billed context per request, so it's now an explicit opt-in. Installs that already enabled it keep it; unset installs default off (no migration seeds memoryEnabled). - C) Settings -> Memory shows a token-cost warning callout when memory is enabled (new settings.memoryTokenCostWarning i18n key, interpolating the configured maxTokens). Tests: no-memory-header.test.ts (5, helper truthiness/case/Headers); memory-settings-default and chatcore-memory-skills-injection aligned to the new off-by-default. 65/65 memory+chatcore tests green; typecheck/lint/file-size/i18n(@65) clean. * test(memory): enable memory in memory-tools test (memory now off by default) The full CI unit suite flagged memory-tools.test.ts 'memory search ...' failing after DEFAULT_MEMORY_SETTINGS.enabled flipped to false: omniroute_memory_search routes through retrieveMemories, which returns [] while memory is disabled (enabled:false → maxTokens 0). The memory MCP tools operate within the memory subsystem, so the test now enables memory explicitly (updateSettings + cache invalidation) — the realistic precondition for a client using the tools. Aligns the test to the intentional off-by-default change; assertions unchanged. |
||
|
|
6f16faa039 |
fix(models): keep vision capability for imported (synced) models (#4264) (#4283)
After importing a provider key, vision-capable models (OpenRouter models whose
architecture declares image input, and other synced providers) were shown as
text-only in /v1/models and the dashboard, even though image requests worked.
Root cause: SyncedAvailableModel never captured a vision flag, and the catalog's
OpenRouter live-enrichment block (which derives vision from architecture.input_modalities)
is skipped once a provider has synced models. So the synced path emitted no vision.
Fix (mirrors the existing supportsThinking capture):
- modelDiscovery.normalizeDiscoveredModels derives supportsVision via the new
detectVisionInput() from architecture.input_modalities, the string
architecture.modality ("text+image->text"), or a top-level input_modalities.
- SyncedAvailableModel gains supportsVision; the read-normalize path preserves it.
- catalog.ts emits capabilities.vision for synced models and merges (not clobbers)
capabilities when the model already exists.
TDD: tests/unit/openrouter-vision-sync-4264.test.ts — capture unit test + an
end-to-end /v1/models assertion (RED before, GREEN after).
Closes #4264
|
||
|
|
550440f65f |
fix(providers): Cloudflare Workers AI discovery uses model names, not UUIDs (#4259) (#4282)
Cloudflare's /ai/models/search returns { id: "<uuid>", name: "@cf/..." } where
name is the callable slug and id is an internal UUID. The cloudflare-ai discovery
config passed the raw objects through (parseResponse: data.result), so buildResponse
used id (the UUID) as the model id — the dashboard/import listed UUIDs instead of
@cf/... model names. Map each result's name -> id (mirrors the gemini/huggingface/
clarifai parseResponse normalizers in the same map); falls through to the local
catalog on error so import never breaks.
TDD: tests/unit/cloudflare-models-uuid-4259.test.ts (RED on UUID ids -> GREEN on slugs).
Closes #4259
|
||
|
|
3c9883bb73 |
Release v3.8.29 (#4126)
OmniRoute v3.8.29 — 115 commits since v3.8.28. Full CHANGELOG + 41 i18n mirrors. All content quality gates green (build, unit 8/8, vitest 188/188, PR test policy, quality gates extended, docs sync, quality ratchet). Remaining red CI checks are pre-existing release flakes (coverage-shard/integration/node-compat teardown), a new transitive undici advisory in electron devDeps, and a workflow-level CodeQL fail (0 open alerts). VPS-validated by the operator. |
||
|
|
f165efcd0b |
Release v3.8.28 (#4053)
* chore(release): open v3.8.28 development cycle * fix(ws): warm SSE auth import on LiveWS startup; relocate boot test to integration (#4063) The live dashboard WebSocket sidecar lazily import()-ed the SSE auth module inside the connection handler, only on the API-key path. That cold import pulls in hundreds of transitive modules and takes ~7s under tsx, blocking the single-threaded event loop. The first API-key WebSocket connection therefore stalled the loop long enough that any connection arriving in that window — e.g. a same-origin cookie client — could not complete its handshake and timed out. This was deterministic, not an "env flake": the boot test fires an API-key connection immediately followed by a cookie connection, so the cookie connection always raced the cold import and timed out (reproduced 3/3 locally and red on every CI run; proven via instrumented probes — reversing the order or warming the module first makes both connections open in ~20ms). Fix: - Memoize the auth-module import and warm it once at startup (before listen), so connection handling never pays the cold-import cost. Real improvement: the first API-key client no longer stalls the event loop for concurrent clients. - Relocate the boot test from tests/unit/cli to tests/integration. It spawns a real subprocess + WS server + SQLite (~9-11s); under the unit suite's --test-concurrency=20 it contended for CPU and destabilized the shard. The serial integration runner is its correct home; it still guards #4004's cookie-parse fix on every PR via the integration CI job. - Bump the test's startup/overall timeouts to absorb the eager auth warm. Makes `npm run test:unit` deterministically green (the only remaining unit red). Validated: relocated test 3/3 green via the integration runner (was 3/3 red); typecheck:core + eslint clean; confirmed it no longer matches the test:unit glob and does match tests/integration/*.test.ts. * fix(ws): start LiveWS sidecar with cwd at package root (#4055) (#4064) * chore(deps): bump ossf/scorecard-action from 2.4.0 to 2.4.3 (#4045) Integrado em release/v3.8.28. Patch de SHA do ossf/scorecard-action (2.4.0→2.4.3), mantém SHA-pin. Reds de CI são exclusivamente os shards flaky pré-existentes branch-wide (Unit 7/8, Integration, Coverage 7/8, Node 1/2) — não relacionados ao bump (PR deps-only). * deps: bump electron from 42.4.0 to 42.4.1 in /electron (#4049) Integrado em release/v3.8.28. Patch do electron (42.4.0→42.4.1). Reds de CI: shards flaky pré-existentes + PR Test Policy = falso-positivo (mudança deps-only sob electron/ não comporta teste de código) + Node 26(2/2) sem step (flake/infra). Precedente #3913/#3914 (electron dependabot mergeado nessas condições). * fix(auto): resolve built-in auto catalog combos (#4058) Integrado em release/v3.8.28. Resolve os IDs de catálogo `auto/*` built-in (combos virtuais) — corrige o 400 "No auto combos configured" em auto/best-coding etc. Ajuste de review: os mapas AUTO_TEMPLATE_VARIANTS/VALID_AUTO_VARIANTS duplicados em chat.ts e chatHelpers.ts foram extraídos para open-sse/services/autoCombo/builtinCatalog.ts (DRY), devolvendo chatHelpers.ts <800 LOC; baseline de chat.ts rebaselinado 1432→1458 (lógica nova). Fast QG + semgrep + dast verdes; 22/22 testes. * chore(docs): update Discord invite link to a non-expiring one (#4067) * chore(deps): freeze @huggingface/transformers in dependabot (hard-pin) (#4066) Integrado em release/v3.8.28. Congela @huggingface/transformers no dependabot (pin exato 3.5.2, load-bearing p/ LLMLingua + memory embeddings, VPS-validado #4014). Fast QG + semgrep + dast verdes. * ci(quality): flip TIA impacted-unit-tests gate from advisory to blocking (#4069) The pre-existing release unit test-debt that kept the TIA "Impacted unit tests" step advisory has been cleared: - #4030 restored 16 lossless Zod/registry reds (from the oyi77 modularize refactors). - #4063 fixed the last red — the LiveWS boot test — which was a real deterministic event-loop stall in the WS sidecar (cold ~7s lazy auth import racing a second connection), not an env flake; fixed (warm the import at startup) and relocated to the integration suite. A full workflow_dispatch ci.yml run on release/v3.8.28 then showed all 8 Unit Tests shards green. The remaining Integration Tests / Quality Ratchet reds are pre-existing and unrelated (combo/resilience env-flakes; eslint/i18n baseline drift). Removing continue-on-error makes PR->release block on unit-test regressions in the TIA-selected impacted set (fail-safe still runs the full unit suite on hub/unmapped changes). typecheck:core was already blocking. Closes the fast-gates "no tests on PR->release" hole (Quality Gate v2 / Fase 9, P2). * docs(compression): document LLMLingua optional deps + on-demand install (#4061) Integrado em release/v3.8.28. Docs LLMLingua optional deps + on-demand install (F3.1). * feat(dashboard): Combo Studio connection-cooldown badge (U1b Slice 2) (#4068) Integrado em release/v3.8.28. Combo Studio connection-cooldown badge (U1b Slice 2 / F5.1). * feat(compression): record Context Editing telemetry (engine: context-editing) (#4062) Integrado em release/v3.8.28. Context Editing telemetry (F4.1). * feat(sse): Context Editing relay coverage + 400-fallback (#4065) Integrado em release/v3.8.28. Context Editing relay coverage (cc-*) + 400-fallback (F4.2/F4.3). Conflito de file-size-baseline.json (vs #4062) resolvido por união (ambas justificativas + base.ts 1292 + chatCore.ts 5898). Validado local no tree mergeado: typecheck:core ✓, eslint ✓, check:file-size ✓, 4/4 testes ✓; semgrep + semgrep-cloud verdes. Fast QG enfileirado (saturação de runner) — mergeado nos gates de política verificados (precedente #4034/#4020). * feat(providers): add OrcaRouter (OpenAI-compatible routing gateway) (#4070) Integrado em release/v3.8.28. Adiciona o provider OrcaRouter (OpenAI-compatible, API-key, DefaultExecutor). Ajuste de review: rebaseline de file-size de providers.ts 3147→3159 (+12 da entrada OrcaRouter). Validado local no tree sincronizado: provider-consistency ✓, docs-counts STRICT 227 ✓, typecheck:core ✓, teste 3/3 ✓, eslint ✓; semgrep + semgrep-cloud verdes. Fast QG/dast enfileirados (saturação de runner) — merge nos gates de política verificados (precedente #4034/#4065). * test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 (#4078) * test(infra): isolate DATA_DIR per test process; raise Stryker concurrency 1→4 Every test process resolved DATA_DIR to the same default (~/.omniroute) when the env var was unset (src/lib/dataPaths.ts::resolveDataDir), so concurrent test files opened the SAME on-disk storage.sqlite. node:test spawns a process per file and Stryker spawns one per sandbox, so this shared file caused cross-file state races: - SQLite lock contention that hung `npm run test:unit` under high --test-concurrency (the ~95-min local hang), and - the non-deterministic baseline that forced stryker.conf.json to concurrency: 1, which in turn could not finish the ~15k-mutant run inside the nightly timeout (the cancelled 2026-06-16/17 nightly-mutation runs) — blocking Quality Gate v2 / Fase 9 Onda 2. open-sse/utils/setupPolyfill.ts could NOT host the fix: it is imported by production (bin/omniroute.mjs, proxyFetch.ts, proxyDispatcher.ts), where redirecting DATA_DIR would point the live SQLite DB at a throwaway temp dir. So this adds a TEST-ONLY tests/_setup/isolateDataDir.ts that gives each process its own temp DATA_DIR when none is set (tests that set DATA_DIR explicitly still win), wired via --import into the test, mutation and CI invocations. Verified: - Stryker dry-run A/B at concurrency=4: FAILS without the isolation import (account-fallback-service tap exit 9, a cross-file race) and PASSES with it. - Full `npm run test:unit` green with isolation (0 fail; a one-off chatcore-translation-paths timeout flake did not reproduce and passes 3/3 isolated) and noticeably faster — the DB lock contention is gone. - New tests/unit/isolate-datadir.test.ts guards the contract (unique temp DATA_DIR when unset; explicit DATA_DIR respected). Wired the --import into: package.json (13 test scripts), stryker.conf.json (tap.nodeArgs + concurrency 1→4), .github/workflows/quality.yml (TIA step), ci.yml (the 5 unit/coverage/integration commands), and bumped nightly-mutation.yml timeout 120→180 for the first cold run before the incremental cache is seeded. * ci(quality): run the TIA gate at CI concurrency (4) to stop oversubscription flakes The TIA "Impacted unit tests" step (made blocking in #4069) ran its fail-safe via `npm run test:unit` — concurrency=20, tuned for multi-core dev machines. On a 4-vCPU CI runner that is 5x oversubscribed, so timing-sensitive tests flake under the load (e.g. `db-backup-extended` "The database connection is not open", `chatcore-translation-paths` upstream-timeout). That intermittently fails a blocking gate on legitimate PRs — exactly what surfaced on the DATA_DIR-isolation PR, whose package.json/workflow changes trip the __RUN_ALL__ fail-safe. Run both the impacted set and the fail-safe at --test-concurrency=4, matching the stable ci.yml unit job. Adds a `test:unit:ci` script (test:unit at concurrency=4). The DATA_DIR isolation in this PR keeps the parallel run race-free, so the only change here is matching the runner's core count. Verified locally: db-backup-extended passes 8/8 in isolation (5 with isolation, 3 without). * docs(quality-gates): reconcile gate inventory with ci.yml + add ROI rationalization backlog (#4095) The "authoritative" gate inventory in QUALITY_GATES.md had drifted from ci.yml: it omitted 9 wired gates — `audit:deps`, `check:tracked-artifacts`, `check:lockfile`, `check:licenses` (lint job), `check:dead-code`, `check:cognitive-complexity`, `check:type-coverage`, `check:codeql-ratchet` (quality-gate job), and `check:pr-evidence` (pr-test-policy job). You can't rationalize an inventory you can't trust, so this reconciles it first. Adds those 9 rows to their job tables and a "Rationalization Backlog (ROI review)" section capturing the Fase 9 Onda 3 findings: mechanical merge/dedup candidates (CVE scanners audit:deps↔osv, the two complexity ESLint passes, cycles↔circular-deps, the two /api anti-hallucination gates, the doubly-run check:docs-sync, check:node-runtime ×11) and the operator-only flip/drop decisions (typecheck:noimplicit vs the type-coverage ratchet, test:vitest:ui parked fails, check:secrets frozen FPs, openapi-security-tiers, pr-evidence, the orphaned semgrep baseline). Also flags the undocumented advisory docs-lint job and the standalone scanner workflows. Docs-only — no gate behavior changes. The merges (CI changes) and flips (policy) are deferred to operator-scoped follow-ups; this PR only makes the map accurate. * test(dashboard): smoke e2e for the Combo Live Studio page (#4075) Integrated into release/v3.8.28 * fix(sse): friendly 413 message for ChatGPT web payload-too-large (#4080) Integrated into release/v3.8.28 * feat(sse): port Claude Code quota-probe bypass + command meta-request helpers (#4083) Integrated into release/v3.8.28 * feat(api): exact offline token counting for count_tokens fallback via tiktoken (#4087) Integrated into release/v3.8.28 * feat(compression): RTK learn/discover (sample source + API + UI) (#4088) Integrated into release/v3.8.28 * feat(dashboard): 2026-06-17 free-tier refresh — honest catalog, uncapped + boost tiers, Layout A budget table (#4089) Integrated into release/v3.8.28 * feat(mitm): capture-pipeline self-test route (Gap 12) (#4093) Integrated into release/v3.8.28 * fix(mitm): crash-safe system-state teardown + socket timeouts (ProxyBridge-inspired hardening) (#4084) Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green) * feat(mitm): attribute intercepted requests to originating process (Gap 1) (#4085) Integrated into release/v3.8.28 (Fast QG TIA red = 3 pre-existing timing flakes verified passing locally 82/82; PR own tests green) * fix(sse): route image requests only to confirmed-vision combo targets (#4071) Integrated into release/v3.8.28 * fix(security): injection guard respects INJECTION_GUARD_MODE DB feature flag (#4077) Integrated into release/v3.8.28 * fix(ws): proxy LAN /live-ws upgrades and add unset JWT_SECRET warning (#4079) Integrated into release/v3.8.28 * fix(dev): force webpack in custom dev server (Turbopack 16.2.x panics) (#4092) Integrated into release/v3.8.28 * ci(quality): dedup the doubly-run check:docs-sync + record validated ROI backlog (#4099) Onda 3 (gate ROI-review) Phase 2. Two parts, both low-risk: 1. Remove the standalone `check:docs-sync` from the `lint` job — it already runs in the `docs-sync-strict` job (via `check:docs-all`) and the husky pre-commit hook, so the `lint`-job copy was a pure duplicate. No coverage lost. 2. Update the Rationalization Backlog in QUALITY_GATES.md with trust-but-verify findings: several "obvious" merges/flips from the ROI review turned out to hide debt and are NOT clean drop-ins — - CVE merge (audit:deps→osv): different semantics (hard high/critical vs regression-ratchet) — keep both. - cycles→circular-deps: dpdm reports 91 cycles (can't promote to blocking) and is broader-scope than the green curated check:cycles — keep both. - openapi-security-tiers flip: blocked by traffic-inspector routes missing the x-loopback-only annotation. - complexity + /api merges: valid but real config/script surgery — deferred. - node-runtime ×11: ~10s savings vs a cheap guard — low ROI, skip. The remaining flips (typecheck:noimplicit, test:vitest:ui, check:secrets, pr-evidence, semgrep) are operator policy decisions, left for the owner. * chore(deps): bump actions/github-script from 7 to 9 (#4046) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/setup-node from 4 to 6 (#4048) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/upload-artifact from 4 to 7 (#4044) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * chore(deps): bump actions/cache from 4.3.0 to 5.0.5 (#4047) Integrated into release/v3.8.28 (dependabot GH-Action bump; SHA-pin preserved) * deps: bump the development group with 10 updates (#4051) Integrated into release/v3.8.28 (dependabot dev group; cyclonedx 4->5 verified compatible with the SBOM invocation --ignore-npm-errors/--output-format JSON/--output-file) * fix(dashboard): event-driven fail-open auto-refresh for embedded log views (#4054) (#4103) The Request Logger gated each auto-refresh tick on a static document.visibilityState === "visible" read. Hosts that report a permanent non-"visible" state without ever firing a visibilitychange event (Docker dashboard wrappers, embedded/proxied webviews) froze auto-refresh entirely — only the manual Refresh button worked, a regression from 3.8.24's unconditional polling. The pause is now event-driven and fail-open: visibleRef starts true and is only flipped to false on a real visibilitychange → hidden transition, so a host that never signals a genuine background transition keeps polling, while normal browser tabs still pause when actually backgrounded. Regression test reproduces the misreporting-host case (RED) and the perf guard is re-encoded under the event-driven semantics. * fix(docker): raise build-stage Node heap to stop production-build OOM (#4076) (#4104) The Docker builder stage ran `npm run build` with V8's default heap ceiling (~2 GB). After #4052 forced the heavier webpack engine (Turbopack panics on this Next.js version), the production optimization pass exceeded that ceiling and the build died with "FATAL ERROR: ... JavaScript heap out of memory" at [builder] npm run build. The builder stage now sets NODE_OPTIONS=--max-old-space-size (default 4096 MB, overridable via --build-arg OMNIROUTE_BUILD_MEMORY_MB) before the build; the value propagates to the spawned next build (resolveNextBuildEnv spreads process.env). Build-only — the runtime heap on the runner stage is unchanged, and CI/local builds (which invoke npm run build directly) are unaffected. Regression guard: tests/unit/dockerfile-build-heap-4076.test.ts asserts the builder stage sets the heap ceiling, before npm run build, at >= 4096 MB. * feat(agent-bridge): portable JSON import/export of config (Gap 4) (#4094) Integrated into release/v3.8.28 * feat(cli): add 'omniroute launch' zero-config Claude Code launcher (#4097) Integrated into release/v3.8.28 (Fast QG TIA red = pre-existing env-doc-contract drift [MITM_IDLE_TIMEOUT_MS/TURBOPACK from #4084/#4092] + opencode-plugin-dist env flake; #4097 own test 3/3 green) * feat(mitm): loop-guard self-check + verbosity control in server.cjs (Gaps 14+15) (#4101) Integrated into release/v3.8.28 (rebased onto release — dropped the already-squash-merged #4084 commits; only the Gaps 14+15 loop-guard/verbosity delta remains) * feat(sse): generic 400 field-downgrade retry + Groq field stripping (#4096) Integrated into release/v3.8.28 * feat(providers): add Wafer AI (Anthropic-compatible, Bearer auth) (#4098) Integrated into release/v3.8.28 * chore(docs) * fix(responses): clear /v1/responses keepalive timer on cancel/abort (timer + CPU leak) (#4105) Integrated into release/v3.8.28 (r7). * perf(gemini): cache reasoning close-tag regex instead of recompiling per token (#4106) Integrated into release/v3.8.28 (r7). * fix(usage): reap orphaned pending-request details (unbounded memory leak) (#4107) Integrated into release/v3.8.28 (r7). * perf(stream): use structuredClone instead of JSON round-trip for per-chunk reasoning split (#4108) Integrated into release/v3.8.28 (r7). * fix(dashboard): restore Update Available banner with npm-binary-free version fallback (#4100) (#4112) getLatestNpmVersion() derived the latest version only from the npm CLI binary and returned null on any error, so Docker/desktop/locked-down installs without npm on PATH silently hid the home banner even when an update existed. Add resolveLatestVersion() (npm CLI -> registry HTTP fallback -> logged warning) and harden version parsing for v-prefix/pre-release strings. Extracted into testable src/lib/system/versionCheck.ts with TDD coverage. * fix(auth): prune expired entries from login brute-force guard map (unbounded growth) (#4111) Integrated into release/v3.8.28 (r8) * fix(logger): hard-cap the error-dedup map to bound memory under unique-message bursts (#4113) Integrated into release/v3.8.28 (r8) * fix(circuit-breaker): enforce MAX_REGISTRY_SIZE (declared but never applied) (#4114) Integrated into release/v3.8.28 (r8) * perf(obfuscation): cache per-word regexes instead of recompiling every request (#4109) Integrated into release/v3.8.28 (r8) * perf(registry): precompute model->provider index in parseModelFromRegistry (#4110) Integrated into release/v3.8.28 (r8) * fix(timers): unref background interval timers so they don't block clean shutdown (#4117) Integrated into release/v3.8.28 (r8) * fix(webhook): clear abort timer in finally to avoid dangling timers on fetch error (#4115) Integrated into release/v3.8.28 (r8) * fix(combo): detach per-target listener from shared hedge abort signal (#4116) Integrated into release/v3.8.28 (r8) * chore(release): finalize v3.8.28 CHANGELOG + reconcile env-doc contract - Build the complete [3.8.28] CHANGELOG section (55 bullets) covering every commit since v3.8.27, grouped by type with PR back-references and human contributor attribution (artickc's memory-leak/perf cluster, OrcaRouter, Wafer AI, MITM gaps, etc.); move the OrcaRouter bullet out of [Unreleased]. - Inject the EN [3.8.28] section into all 41 i18n CHANGELOG mirrors (parity). - Reconcile the env/docs contract: document MITM_IDLE_TIMEOUT_MS + MITM_VERBOSE in .env.example and ENVIRONMENT.md; allowlist the framework-internal TURBOPACK and the Claude Code ANTHROPIC_AUTH_TOKEN in check-env-doc-sync. - Fix 3 broken relative links in docs/providers/AGENTROUTER.md (regressed when the file was relocated this cycle) so docs-sync-strict passes. * fix(quality): treat test→test renames as relocations, not deletions The anti-test-masking gate's subcheck-1 collected deleted AND renamed test files via `--diff-filter=DR --name-only` and flagged every one as "deleted — human review required", contradicting its own documented contract ("DELETADOS ou renomeados-e-NÃO-substituídos"): a rename test→test IS a substitution (the test moved, coverage preserved). This false-positived on #4063's legitimate relocation of live-ws-startup.test.ts (unit/cli → integration, asserts 2→2) and would block every PR that relocates a test — surfacing only at release-day because the Fast QG (PR→release) doesn't run test-masking. The gate now parses `--name-status -M`: true deletions and test→non-test renames still flag; a test→test rename is run through the assert-reduction check across the move, so a clean relocation passes while gutting-via-rename (dropped asserts / new tautologies / skips) still fires. Adds partitionDeletedRenamed + 6 regression tests. --------- Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Demiurge The Single <megamen932@gmail.com> Co-authored-by: jinhaosong-source <jinhao.song@myflashcloud.com> Co-authored-by: diego-anselmo <contato@diegoanselmo.com.br> Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com> Co-authored-by: Rahul sharma <sharmaR0810@gmail.com> Co-authored-by: Chirag Singhal <76880977+chirag127@users.noreply.github.com> Co-authored-by: NOXX - Commiter <artur1992123@mail.ru> |
||
|
|
fa367dd99e |
Release v3.8.27 (#3968)
* chore(release): open v3.8.27 development cycle * fix(security): polynomial ReDoS in comboAgentMiddleware regex (#3982) * fix(security): eliminate polynomial ReDoS in comboAgentMiddleware <omniModel> regex (CodeQL js/polynomial-redos) CACHE_TAG_PATTERN wrapped the tag in an unbounded `(?:\\n|\n|\r)*` prefix/suffix. On an unanchored `.test()`/`.exec()` that is O(n²) on inputs with many newlines (CodeQL js/polynomial-redos, alerts #612/#613). The surrounding runs are irrelevant to detecting/capturing the tag, so the detection pattern now matches only the core `<omniModel>([^<]+)</omniModel>`; the global strip pattern still consumes the wrapping newlines (combo.ts streaming, #531) but BOUNDED ({0,16}) so it stays linear. Behavior preserved: detection, model extraction, multi-tag stripping (#454) and blank-line cleanup all unchanged (107 related tests green). Adds ReDoS-safety regression tests (50k-newline inputs complete in <1ms). * docs(changelog): add #3982 ReDoS fix to [3.8.27] * ci(security): harden workflows — artipacked persist-credentials + cache-poisoning + SC2086 (#3965) * Refine provider quota card display (#3969) Integrated into release/v3.8.27 * feat: add sidebar group separator toggles (#3971) Integrated into release/v3.8.27 * Gate control-plane proxy direct fallback (#3963) Integrated into release/v3.8.27 * Capture actual upstream provider requests (#3941) Integrated into release/v3.8.27 * ci(quality): flip require-tighten + osv + Trivy to blocking (v3.8.27 cycle-end) (#3984) * fix(resilience): respect connection cooldown stored as numeric epoch (#3954) (#3995) rate_limited_until is a TEXT column, but setConnectionRateLimitUntil (Antigravity full-quota path) persists a raw epoch number that SQLite coerces to a numeric string ("1781696905131.0"). The selection predicate isAccountUnavailable then did new Date("1781696905131.0") -> NaN, so the cooling connection was never skipped and the router kept dispatching to rate-limited accounts. Normalize numeric-epoch strings (and number/Date/ISO) via a shared cooldownUntilMs() helper in isAccountUnavailable / getEarliestRateLimitedUntil / filterAvailableAccounts / parseFutureDateMs. ISO behavior preserved. * fix(providers): fetch live /models for LLM7 and BytePlus (#3976) (#3996) llm7 and byteplus carry a real modelsUrl but were not classified by any live-fetch branch of the model-import route, so their hardcoded 4-entry registry catalog was served (source local_catalog) instead of the upstream catalog. Add both to NAMED_OPENAI_STYLE_PROVIDERS so the route probes <baseUrl>/models and serves the live list, falling back to the local catalog only on fetch failure. * fix(dashboard): logs auto-refresh reads live visibility, not a stale mount ref (#3972) (#3997) The auto-refresh interval gated each tick on visibleRef, seeded once at mount and updated only by a visibilitychange event. A tab mounted while document.visibilityState is 'hidden' (background load, bfcache, embedded/proxied webviews) with no later visibilitychange left the ref false forever, so the interval ticked but never fetched — only the manual button worked. Read the live document.visibilityState in the tick instead. * feat(compression): add Indonesian caveman rules and language pack (#3975) Integrated into release/v3.8.27 (cherry picked from commit |
||
|
|
81a37b67ed |
Release v3.8.26 (#3875)
OmniRoute v3.8.26 — see CHANGELOG.md [3.8.26] for the full notes. Highlights: Vertex AI media generation (#3929), GLM-5.2 effort-tier routing (#3885), sticky round-robin combos (#3846), OpenRouter connection presets (#3878), compression prompt-cache fix (#3936/#3890), and a security pass (form-data/vite + workflow hardening, #3949). Co-authored-by: artickc <artickc@users.noreply.github.com> Co-authored-by: rdself <rdself@users.noreply.github.com> Co-authored-by: herjarsa <herjarsa@users.noreply.github.com> Co-authored-by: Jack Smith <16862258+YunyunZhai@users.noreply.github.com> Co-authored-by: dhaern <dhaern@users.noreply.github.com> Co-authored-by: adivekar-utexas <adivekar-utexas@users.noreply.github.com> Co-authored-by: megamen32 <megamen32@users.noreply.github.com> Co-authored-by: zhiru <zhiru@users.noreply.github.com> Co-authored-by: insoln <insoln@users.noreply.github.com> Co-authored-by: diego-anselmo <diego-anselmo@users.noreply.github.com> |
||
|
|
35dbf0eea1 |
Release v3.8.25 (#3866)
* chore(release): continue v3.8.25 development cycle after main code-sync (r5) main fast-forwarded to release/v3.8.25 (#3863): unblocked Build+Docker via #3864, plus #3837 (mimocode proxy) and #3862 (trivy bump). This marker re-opens the umbrella PR for further v3.8.25 work. No version bump. * fix(db): persist the Keep-latest-backups retention setting (#3834) (#3867) * fix(oauth): clear GitLab Duo setup message instead of 500 (#3861) (#3868) * test(oauth): prove refresh_token preserved on real gemini-cli/antigravity dispatch (#3850) (#3869) * feat(compression-ui): unified compression config UI — per-engine pages + combos editor + menu + WS default-on (#3860) Integrated into release/v3.8.25 — feat(compression-ui): unified compression configuration UI (Compression Hub + per-engine Lite/Aggressive/Ultra pages + combos editor + sidebar entry + live-WS default-on). File-size re-baselined for sidebarVisibility.ts/chatCore.ts growth; orphan ws test relocated to a collected path. * docs(changelog): complete the v3.8.25 release notes + credit all contributors Audited every commit since v3.8.24 and filled the gaps the [3.8.25] section was missing: a New Features section (compression engines + Compression Studios #3848, compression UI #3860, injection-guard #3857, kiro discovery #3836, Veo #3839, mimocode proxy #3837, Arena ELO flag #3821), 9 more Fixed entries (#3811/#3807/#3759/#3849/#3838/#3835/#3814/#3820/#3819), a Security section (CCR IDOR #3859, supply-chain #3824), and an Internal/Quality section. Every contributor and issue reporter is now credited. * docs(changelog): restore + complete the v3.8.25 release notes Re-adds CHANGELOG.md (a prior server-side commit accidentally dropped it) with the complete, audited [3.8.25] section: New Features, the full Fixed list, Security & Hardening, and Internal/Quality — every contributor and issue reporter credited. * chore(release): finalize v3.8.25 — reconcile CHANGELOG + i18n mirrors, document OMNIROUTE_MAX_PENDING_MIGRATIONS, green the unit suite Release-gate reconciliation for v3.8.25: - CHANGELOG: dated 2026-06-14, linked #3826, rolled up file-size re-baselines (#3823/#3833), recorded the test-greening; re-synced all 41 i18n CHANGELOG mirrors. - Documented OMNIROUTE_MAX_PENDING_MIGRATIONS (#3416) in .env.example + ENVIRONMENT.md. - Greened the unit suite (was merged red on 4 CI shards): aligned 10 stale tests to this cycle's intended behavior (#3838/#3822/#3501/SOCKS5/Vertex-Express/Antigravity) and the same-provider 503 fall-through test; de-flaked the compression benchmark reproducibility and ServiceSupervisor crash tests. No production code changed. * ci(security): clear OpenSSF Scorecard code-scanning noise + harden workflow token permissions The Security tab held 155 open alerts, ALL from the advisory OpenSSF Scorecard tool (#3824) — supply-chain/posture scores, not code vulnerabilities — which drowned out real CodeQL findings. - scorecard.yml: stop uploading SARIF to the code-scanning tab (drop the upload-sarif step + the now-unused security-events: write). The run still produces the OpenSSF badge (publish_results) and a downloadable SARIF artifact. - TokenPermissions hardening (the high-severity, genuinely-valuable subset): set each workflow's top-level token to read-only and grant the exact writes at the job level that needs them — npm-publish (id-token/packages on publish jobs), docker-publish (packages on build), electron-release (contents on build/release, id-token/packages on publish-npm), build-fork (packages on build), claude (empty top-level; job grants its own). The 155 existing alerts were dismissed. Not adopting repo-wide SHA-pinning (143 PinnedDependencies advisories) — declined. * test(integration): align stale wiring/socks5 integration tests to this cycle's behavior These were red on the CI Integration job (pre-existing). No production code changed: - integration-wiring: the combos page no longer renders a per-page EmailPrivacyToggle (#3822 consolidated it into Settings → Appearance); the provider-detail test-result masking and upstream-proxy copy moved to decomposed components (#3501 BatchTestResultsModal / UpstreamProxyCard) — assertions now read the owning files. - api-routes-critical: SOCKS5 is now enabled by default (opt-out), so the disabled- rejection test must set ENABLE_SOCKS5_PROXY=false explicitly (an unset env now means enabled). (The ~32 live-Gemini integration tests are gated on OMNIROUTE_API_KEY and skip in CI; they only 'fail' locally when that key is present without a running server.) |
||
|
|
f42e8fa751 |
feat(mimocode): per-account proxy support for multi-account round-robin (#3837)
Integrated into release/v3.8.25 — feat(mimocode): per-account proxy for multi-account round-robin (runWithProxyContext per account, keyed by fingerprint). Orphan test relocated to a collected vitest path (14/14 green). |
||
|
|
337cd18932 | fix(sse): clamp Gemini thinking budget to model cap (#3842) (#3865) | ||
|
|
d728bfbb1e |
Fase 8 · Bloco D — injection-guard em todas as rotas LLM + red-team (#3857)
Integrated into release/v3.8.25 — Fase 8 Bloco D (injection-guard em todas as rotas LLM + red-team). |
||
|
|
4ffc55cfe4 |
feat(compression): compression engines + async pipeline + Compression Studios (#3848)
Integrated into release/v3.8.25. |
||
|
|
c8b9544d54 | test(proxy): guard per-connection direct bypass over global proxy (#2996) (#3853) | ||
|
|
7c080941d1 | feat(connections): per-connection disable-cooldown opt-out (#2997) (#3852) | ||
|
|
2670a0a819 |
docs(ui): clarify routing settings copy for strategy sync + sticky limit (#3843)
Clarifies that the Default Strategy control syncs both new combo defaults and global account fallback routing, and updates the Round Robin sticky-limit helper text to call out account-level fallback behavior. Copy-only change to ComboDefaultsTab + en.json. Integrated into release/v3.8.25. Co-authored-by: Abhishek Divekar <adivekar@utexas.edu> |
||
|
|
948cf1f92c |
feat(kiro): live per-account model discovery via ListAvailableModels (#3836)
Kiro's catalog is per-account / per-tier (and admin-curated for IAM Identity Center orgs), which the static registry can't reflect. The models route now discovers the live list from the CodeWhisperer ListAvailableModels API with the stored OAuth token (Builder ID / social and IdC accounts; profileArn only as a retry to avoid 403, region-matched with us-east-1 fallback), falling back to the static registry catalog when the token is missing/expired or the upstream is unavailable so import never breaks. Integrated into release/v3.8.25. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
ed0638c0f1 |
feat(gemini/vertex): surface Veo video models in dynamic discovery (#3839)
Gemini / Vertex / Vertex AI Express already discover their catalog dynamically from v1beta/models, but video (Veo) models use predictLongRunning, which was not mapped — so they never surfaced. parseGeminiModelsList now recognizes predictLongRunning and exposes Veo video models alongside chat/image/embedding/audio. Integrated into release/v3.8.25. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
058946bd04 |
fix(models): don't auto-hide transient (rate-limited/timeout) failures on Test All (#3849)
With Auto-hide failed models on (default), a Test All sweep across 10+ models in parallel reliably trips per-account rate limits on subscription-tier providers, and the 429'd/timed-out models were auto-hidden — silently removing working models from /v1/models with no easy recovery. evaluateTestAllEntry now surfaces transient failures (rateLimited/isTimeout) as an 'error' icon but keeps them visible; only genuine (non-transient) failures are still auto-hidden. Integrated into release/v3.8.25. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
bcb7ed00c7 |
fix(pricing): add missing Kiro model pricing rows (#3835)
The kiro table in DEFAULT_PRICING was missing models the Kiro registry serves (most visibly claude-sonnet-4.6), so getPricingForModel() returned null and their usage cost was reported as $0.00. Adds the missing rows. Integrated into release/v3.8.25. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
315ac98b49 |
fix(i18n): translate missing embeddedServices keys across 37 locales (#3819)
Fills the previously-untranslated embeddedServices / embeddedServicesSubtitle keys (__MISSING__ placeholders) with proper translations in 37 locale message files, improving UI key coverage. JSON validated; i18n UI-coverage gate (threshold 65) passes. Integrated into release/v3.8.25. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
f2f909bd7f |
fix(ui): expand request log table height with vertical resize (#3820)
The request log table is given a comfortable minimum height (~10 rows) and is user-resizable vertically, replacing the previous flex/overflow-hidden constraints that clipped it short. Pure layout change to the logs page and RequestLoggerV2 card. Integrated into release/v3.8.25. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
ef07a19de6 |
fix(ui): render country flags via flagcdn SVGs for Windows compatibility (#3814)
Windows does not render regional-indicator flag emojis. The LanguageSelector now maps a flag emoji's regional-indicator code points to an ISO country code and renders the flag from flagcdn, falling back to the raw emoji span when the glyph is not a two-letter regional pair or the image fails to load (onError). Integrated into release/v3.8.25. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com> |
||
|
|
772e6ba493 |
Consolidate email privacy control into Settings (#3822)
Moves the account email visibility control into Settings › Appearance (above Show Sidebar Items) and removes the page-level email reveal buttons from combos, logs, provider detail, provider quota, quota sharing, and the edit-connection modal. The global masking state is unchanged — existing account labels still consume the shared emailPrivacyStore — so one toggle now governs masking everywhere. The old EmailPrivacyToggle component is replaced by AccountEmailVisibilitySetting. Integrated into release/v3.8.25. Co-authored-by: R.D. <rogerproself@gmail.com> |
||
|
|
31e4e46ef9 |
Expose Arena ELO sync in feature flags (#3821)
Adds ARENA_ELO_SYNC_ENABLED to the Dashboard Feature Flags registry (DB-overridable), routes Arena ELO startup/status checks through the shared feature-flag resolver while preserving the existing env fallback, and refreshes env docs (adds the missing STREAM_READINESS_TIMEOUT_MS example) so env/doc sync stays green. Integrated into release/v3.8.25. Co-authored-by: R.D. <rogerproself@gmail.com> |
||
|
|
5875c7993f | fix(providers): surface real Devin error + fix Windsurf auth instructions (#3324) (#3829) | ||
|
|
c9e24ae48c | fix(grok-web): clearer 403 message for anti-bot/IP-reputation blocks (#3474) (#3830) | ||
|
|
3e79d92744 | fix(db): env-overridable mass-pending-migrations threshold (#3416) (#3827) | ||
|
|
826c533a59 | fix(sse): retry once on STREAM_EARLY_EOF for single-model requests (#3758) (#3817) | ||
|
|
ef324cd00e |
fix(models): preserve eye-hidden models across auto-sync (#3782) (#3816)
* fix(models): preserve eye-hidden models across auto-sync (#3782) * chore(quality): re-baseline file-size for models.ts growth (#3782) |
||
|
|
e952ae1406 | fix(providers): correct lmarena cookie hint to arena-auth-prod-v1 (#3810) (#3815) | ||
|
|
6781a843f2 |
fix: stream routed SSE chunks promptly (#3759)
Reworks stream readiness as a ping/zombie filter instead of a semantic content gate: downstream streaming is released as soon as any structured non-ping SSE event arrives, replaying the buffered prefix. Removes the fixed 2s first-byte cap (readiness now inherits REQUEST_TIMEOUT_MS unless STREAM_READINESS_TIMEOUT_MS is set) so slow first-byte reasoning providers no longer false-504. Combo stream quality stays strict: validateResponseQuality still requires an actual content_block / known non-Claude payload before accepting a routed target. Also normalizes multi-line data: framing, metadata-prefixed events, and final events that arrive without a trailing blank line. Integrated into release/v3.8.25. Co-authored-by: R.D. <rogerproself@gmail.com> |
||
|
|
e38d225124 |
fix(intelligence): run pricing + models.dev sync from the live startup path (#3806)
Wires initPricingSync + initModelsDevSync into instrumentation-node.ts (self-gated, opt-in preserved) so they actually run in the standalone runtime. |