Commit Graph

4367 Commits

Author SHA1 Message Date
diegosouzapw
549e2aeeb8 docs(changelog): add #3358 Gemini textual tool-call normalization to v3.8.14 2026-06-07 07:11:00 -03:00
Ardem2025
cb46aeb96c fix(gemini): resolve truncation/suppression of false positive textual tool call markers in backticks (#3358)
Integrated into release/v3.8.14 — Gemini/Antigravity textual tool-call marker normalization (no false-positive suppression + split-chunk buffering).
2026-06-07 07:10:13 -03:00
Diego Rodrigues de Sa e Souza
95cdde5f90 fix(translator): coerce Gemini functionDeclaration parameters to an OBJECT schema (#3357) (#3360) 2026-06-07 07:02:23 -03:00
diegosouzapw
8f7172122c chore(release): finalize v3.8.14 changelog + clear release-gate drift
- CHANGELOG: finalize the v3.8.14 section (date, full New Features/Bug Fixes/
  Maintenance coverage of all 16 cycle commits, Contributors hall of 12).
- docs: document OMNIROUTE_BROWSER_POOL + WEB_COOKIE_USE_BROWSER (#3323) in
  .env.example + ENVIRONMENT.md; regenerate the id/llm.txt strict mirror (#3348
  had translated it; llm.txt mirrors must match root).
- test(proxy-fetch): #3323 made tlsClient.available a computed getter — stub it
  via Object.defineProperty instead of assignment (5 tests were red on the base).
2026-06-07 03:22:32 -03:00
Diego Rodrigues de Sa e Souza
3dd3480b3c fix(electron): tree-kill the server on exit/update to release the omniroute.exe lock (#3347) (#3354) 2026-06-07 02:48:49 -03:00
Diego Rodrigues de Sa e Souza
67b1cda49d fix(dashboard): stop infinite config-load loop on Hermes Agent detail page (#3353) 2026-06-07 02:18:08 -03:00
Paijo
1a4d2fc4be fix(noauth): expose only usable model aliases (#3345)
Integrated into release/v3.8.14 — noauth usable-alias filtering + registry alias plumbing (veo-free).
2026-06-07 02:16:47 -03:00
Paijo
2271689d19 fix(duckduckgo): restore bare Response contract and rebase onto release/v3.8.14 (#3323)
Integrated into release/v3.8.14 — browser-backed cookie providers (duckduckgo/claude-web) with restored executor contract + unit tests.
2026-06-07 02:13:23 -03:00
Wilson
31c9d5b726 fix(providers): reduce proxy label noise (#3346)
Integrated into release/v3.8.14 — reduce proxy label noise + a11y (aria-label/sr-only).
2026-06-07 02:09:52 -03:00
Diego Rodrigues de Sa e Souza
4317b431e6 fix(dashboard): remove duplicate Distribute Proxies button on provider page (#3352) 2026-06-07 02:07:44 -03:00
Randi
da16a173a8 fix(provider-proxy): honor per-account proxy toggles (#3349)
Integrated into release/v3.8.14 — honor per-account proxy toggles + auto-fallback opt-in via PROXY_AUTO_SELECT_ENABLED.
2026-06-07 02:06:45 -03:00
Diego Rodrigues de Sa e Souza
9c2beb7312 fix(review): resolve /review-reviews battery findings (LEDGER-1..11) on v3.8.14 (#3350)
Integrated into release/v3.8.14 — /review-reviews battery hardening (LEDGER-1..11) for #3338 custom-headers + #3333 kiro, plus cycle-test drift fixes (#3329/#3330/#3332).
2026-06-07 01:57:54 -03:00
Krisna Santosa
559b97c0e8 docs(i18n): translate 25 core documentation files to Indonesian (#3348)
Integrated into release/v3.8.14 — Indonesian i18n docs.
2026-06-07 01:56:25 -03:00
Diego Rodrigues de Sa e Souza
1306e7b3f1 fix(sse): treat MiniMax M3 as multimodal so vision isn't stripped (#3328) (#3342)
MiniMax M3 via the opencode provider (oc/minimax-m3-free) appeared blind:
image inputs didn't reach the model, while the same model in Cline could
see them. Verified empirically that MiniMax M3 on the opencode upstream IS
multimodal -- a base64 image is described correctly (it returns 403 only
for remote image URLs, which it doesn't accept).

Root cause: OmniRoute treated MiniMax M3 as a non-vision model in two
places, so when compression was active the image was replaced with a text
placeholder before dispatch:
- compression's modelSupportsVision() heuristic (lite.ts) only matched
  gpt-4/4o/claude-3/gemini/vision -- minimax was absent -> replaceImageUrls
  stripped the image.
- the opencode minimax-m3-free catalog entry lacked supportsVision, so the
  combo vision-capability gate could also exclude/mishandle it.

Add 'minimax-m3' to the vision heuristic and supportsVision: true to the
opencode minimax-m3-free entry. TDD: a failing-then-passing test in
compression/lite.test.ts proves replaceImageUrls now keeps images for
minimax-m3 ids, plus a registry assertion mirroring the #2822 qwen test.

Reported-by: @mikmaneggahommie
2026-06-06 23:20:11 -03:00
Diego Rodrigues de Sa e Souza
f89b5c5e46 fix(proxy): make auto-selection fallback opt-in (#3332) (#3344)
selectWorkingProxyFallback (Step 11 of resolveProxyForConnection) listed ALL
registry proxies, ignoring assignments and per-connection proxy_enabled, and
returned the first working one with level:'autoSelect'. So a single proxy added
to the registry silently became a global fallback for every connection's traffic.

Gate it behind a new PROXY_AUTO_SELECT_ENABLED feature flag (default off): the
fallback now no-ops unless the operator opts in. No registry proxy becomes a
silent global default anymore.

Co-authored-by: hertznsk <hertznsk@users.noreply.github.com>
2026-06-06 22:58:18 -03:00
Diego Rodrigues de Sa e Souza
23d7bd1589 fix(cli): write OpenCode config to ~/.config on all platforms incl. Windows (#3330) (#3343)
resolveOpencodeConfigDir used %APPDATA% on Windows, but OpenCode reads its
config from XDG ~/.config/opencode/ on every platform (on Windows:
%USERPROFILE%\.config\opencode\, NOT %APPDATA%). So a Windows user who
configured OpenCode via the dashboard had the file written where OpenCode never
looks — it silently had no effect.

Use the XDG path (XDG_CONFIG_HOME || ~/.config) unconditionally. Update the UI
note + route JSDoc, and flip the three tests that encoded the old %APPDATA%
behavior (t40 per-platform + card-note, cli-runtime-extended getCliConfigPaths).

Co-authored-by: abdulkadirozyurt <abdulkadirozyurt@users.noreply.github.com>
2026-06-06 22:52:05 -03:00
Diego Rodrigues de Sa e Souza
bb55a804e9 fix(catalog): remove minimaxai/minimax-m3 from NVIDIA NIM tier (404 upstream) (#3329) (#3341)
NVIDIA NIM does not host minimaxai/minimax-m3 — every request returns
404 page not found, while sibling minimaxai/minimax-m2.7 on the same provider
works. Advertising a model that 404s is a catalog bug; remove it from the nvidia
tier (it remains on the tiers that actually serve MiniMax M3). Re-add only once
NVIDIA serves it.

Co-authored-by: mikmaneggahommie <mikmaneggahommie@users.noreply.github.com>
2026-06-06 22:48:01 -03:00
Dong Mengzhe
54364d1aec Improve code quality: auto-pr/docstrings-1780792063 (#3337)
Integrated into release/v3.8.14 — docstring for context analytics route re-export.
2026-06-06 22:38:28 -03:00
Someres
2c67b568db fix: Kiro Builder ID token import fails with Bad credentials (#3333)
Integrated into release/v3.8.14 — adds Builder ID cached-creds + OIDC refresh path for Kiro token import, with regression tests (#3333).
2026-06-06 22:38:11 -03:00
PizzaV
ec3a2af0ea feat: add per-provider custom headers support for OpenAI/Anthropic-compatible nodes (#3338)
Integrated into release/v3.8.14
2026-06-06 22:35:44 -03:00
diegosouzapw
ee24068872 chore(release): open v3.8.14 development cycle
Version bump 3.8.13 -> 3.8.14 (root + electron + open-sse + openapi + lockfiles).
Seed the v3.8.14 changelog with the four post-tag hotfixes that shipped to
Docker/Electron in v3.8.13 but missed the immutable npm 3.8.13 (#3336 SSRF /
CodeQL #323, #3334/#3335/#3339 Electron packaging). i18n CHANGELOG mirrors get
the in-progress placeholder section.
2026-06-06 22:07:28 -03:00
Diego Rodrigues de Sa e Souza
630baa6c18 fix(electron): swallow auto-updater check rejection to avoid unhandled rejection (#3339)
checkForUpdates() is fired unawaited from a setTimeout at startup. The
underlying autoUpdater.checkForUpdates() rejects on a 404 (release update
manifest not published yet), offline, or rate-limit — and the uncaught
rejection surfaced as an "Unhandled Rejection", which the packaged-app smoke
test treats as fatal (failed the macOS-intel v3.8.13 build; passed elsewhere
only by timing race). The autoUpdater "error" event still notifies the user;
wrap the await so the promise rejection never escapes. Adds a regression test.
v3.8.13
2026-06-06 21:42:30 -03:00
Diego Rodrigues de Sa e Souza
df2379053e fix(security): use trusted internal origin for provider auto-sync self-fetch (CodeQL #323 SSRF) (#3336)
POST /api/providers fires a credential-bearing self-fetch to the new
connection's /sync-models route (forwarding the management cookie + internal
sync auth headers). #3267 built that origin from new URL(request.url).origin —
the client-controlled Host header — so a (management-authenticated) caller
could redirect the internal request to an arbitrary host, exfiltrating the
internal sync auth token (CodeQL js/request-forgery, critical, alert #323).

Derive the origin from the trusted loopback/env-pinned base URL via a new
getModelSyncInternalBaseUrl() helper (same source the model-sync scheduler
already uses), never from the incoming request. Adds a regression test.
2026-06-06 21:20:26 -03:00
Diego Rodrigues de Sa e Souza
9535fa52a6 fix(startup): correct autoRefreshDaemon import alias (@/ -> @omniroute/open-sse) (#3292) (#3335)
instrumentation-node.ts imported the #3292 cookie auto-refresh daemon via
"@/open-sse/services/autoRefreshDaemon". The @/ alias maps to src/, but the
daemon lives in the open-sse workspace, so the import resolved to the
non-existent src/open-sse/... and threw "Cannot find module" at runtime in the
built standalone. A try/catch made it non-fatal (the daemon silently never
ran), which kept typecheck and the dev server green, but the packaged Electron
app's strict startup-log smoke test failed on the "Cannot find module" line.

Use the correct @omniroute/open-sse alias, plus a regression test banning
@/open-sse/* imports across src/.
2026-06-06 21:15:43 -03:00
Diego Rodrigues de Sa e Souza
cd89ce3cfa fix(electron): ship loginManager.js in the packaged app (#3292 regression) (#3334)
#3292 added electron/loginManager.js and a require("./loginManager") in
main.js but did not add it to electron-builder's build.files allowlist, so
the packaged app crashed at startup with "Cannot find module './loginManager'"
on the Linux/macOS smoke tests (v3.8.13 Electron release fragment).

Add loginManager.js to build.files, plus a regression test that asserts every
local require("./x") in the Electron entry points is shipped.
2026-06-06 20:50:02 -03:00
Diego Rodrigues de Sa e Souza
a25d5f1ef6 Release v3.8.13 (#3327)
* chore(release): open v3.8.13 development cycle

Bump 3.8.12 → 3.8.13 across package.json, lockfile, electron/, open-sse/, and
docs/reference/openapi.yaml; add the [3.8.13] cycle placeholder to the root
CHANGELOG and the 41 i18n mirrors. Integration branch for the v3.8.13 cycle —
fixes/features land here via per-issue PRs and it merges to main at release time.

* fix(ci): skip auto-deploy when VPS host is unreachable from the runner (#3299)

Integrated into release/v3.8.13

* fix(dev): auto-rebuild better-sqlite3 on Node ABI mismatch at dev startup (#3301)

Integrated into release/v3.8.13

* feat(api): accept path-scoped API keys on client API routes (#3300)

Integrated into release/v3.8.13

* fix(sse): harden against empty responses causing Copilot Chat failures (#3297)

Integrated into release/v3.8.13

* fix(api): remove Completions.me rickroll provider (discussion #3293) (#3302)

Integrated into release/v3.8.13

* fix(opencode-provider): extract contextLength from live model catalog (#3298)

Integrated into release/v3.8.13

* feat(web-cookie): self-service login infrastructure + auto-refresh daemon (#3292)

Integrated into release/v3.8.13

* docs(changelog): record the v3.8.13 PRs merged this round (#3292/#3300/#3297/#3298/#3301/#3302/#3299)

* fix(auth): harden URL token extraction — drop query-string fallback, gate to client routes (security follow-up to #3300) (#3309)

Security follow-up to #3300 — integrated into release/v3.8.13

* docs: rename resolve-issues → review-issues skill references

* fix(dashboard): keep no-auth providers visible under 'Show configured only' (#3290) (#3312)

no-auth providers (opencode, duckduckgo-web, theoldllm, veoaifree-web) never
create a DB connection row so stats.total stays 0, which the configured-only
filter treated as 'unconfigured' and hid them — even though they are always
usable and appear unconditionally in /v1/models. filterConfiguredProviderEntries
now treats displayAuthType === 'no-auth' as configured.

Co-authored-by: uniQta <uniQta@users.noreply.github.com>

* fix(cli): resolve update paths relative to script + recursive backup (#3295) (#3313)

omniroute update always failed on a global install:
- getCurrentVersion() read package.json from process.cwd(), which on a global
  npm/brew install is the user's working dir, not the package root → null →
  'Could not determine current version'.
- createBackup() resolved bin/ from cwd too, and passed the 'cli' directory to
  copyFileSync → EISDIR, swallowed by the catch → 'Failed to create backup'.

Both now resolve package.json/bin relative to the script via import.meta.url,
and the backup uses cpSync({recursive:true}) so the cli/ directory is copied.

Co-authored-by: uniQta <uniQta@users.noreply.github.com>

* fix(theoldllm): read upstream body once to avoid [502] body-already-read (#3296) (#3314)

On the cached-token path the executor never enters the refresh branch, so the
same upstream Response was read with .text() twice (token-rejection check +
final body). A Response body is single-use, so the second read threw
'Body is unusable: Body has already been read', caught and surfaced as [502].

Read the body once into finalBody and only re-read after a token-rejection
refetch.

Co-authored-by: onizukashonan14-png <onizukashonan14-png@users.noreply.github.com>

* fix(sse): strip leaked internal tool envelopes from streaming output (#3311)

Integrated into release/v3.8.13

* fix(sse): expose Claude + Gemini budget tiers in the antigravity catalog (#3184) (#3303)

Integrated into release/v3.8.13 (#3184)

* fix(catalog): compute combo context_length from known targets only (#3304)

Integrated into release/v3.8.13 — live contextLength + known-targets combo context (#3298 follow-up)

* chore(i18n): add message keys for proxy UI + vscode/ollama endpoint (#3307)

Integrated into release/v3.8.13 — i18n message keys for proxy UI + vscode/ollama

* feat(dashboard): i18n the proxy settings UI (#3310)

Integrated into release/v3.8.13 — i18n the proxy settings UI

* feat(api): model catalog enrichment + MCP model-catalog tools (#3306)

Integrated into release/v3.8.13 — model catalog enrichment + MCP model-catalog tools, reconciled with #3309 URL-token hardening

* test(catalog): align Antigravity preview-alias test with #3303 budget tiers

#3303 added the Gemini `-high`/`-low` budget tiers to ANTIGRAVITY_PUBLIC_MODELS
(user-callable on the Antigravity OAuth backend, verified via #3184), but did
not update the catalog-route test that asserted `antigravity/gemini-3.1-pro-high`
must NOT be exposed. The assertion now reflects the intended behavior — the
client-visible budget alias IS surfaced — while keeping the legacy
`gemini-claude-*` alias keys unexposed. Caught running the full catalog suite
on the merged release HEAD (the #3303 round only ran the antigravity-aliases
and usage-hardening files).

* docs(changelog): record the 6 PRs merged this review round into v3.8.13

#3306/#3307/#3310 (New Features — VS Code split: catalog+MCP, i18n keys, proxy
UI i18n), #3311/#3303/#3304 (Bug Fixes — SSE envelope sanitizer, antigravity
budget tiers, combo known-targets context_length).

* chore(release): finalize v3.8.13 changelog and cleanup

Finalize the v3.8.13 changelog with release date, maintenance notes,
and contributor credits. Update MCP docs to reference the correct tool
inventory diagram, exclude nested .claude worktrees from ESLint scans,
and tighten a response sanitizer type guard.

* fix(dashboard): refresh connections after provider auth import (#3320)

Integrated into release/v3.8.13 — refresh connections after provider auth import

* fix(codex): strip client-only params on native /responses passthrough (#3317) (#3325)

A /v1/responses request against the built-in codex/ provider does an
openai-responses -> openai-responses passthrough (CodexExecutor.transformRequest
returns the body early for _nativeCodexPassthrough). It forwarded client-only
fields verbatim and the Codex upstream rejected them with 400 Unsupported
parameter: prompt_cache_retention / safety_identifier / user — breaking Factory
Droid (which injects all three). The chat-completions path already strips these
(base.ts #1884, openai-responses translator #2770) but the passthrough skips
translation. Strip the three fields in the shared block before the passthrough
return; user is removed unconditionally since Codex /responses always rejects it.

Co-authored-by: tycronk20 <tycronk20@users.noreply.github.com>

* fix(dashboard): normalize agent-bridge /state response to stop page crash (#3318) (#3326)

The Agent Bridge page seeded a well-shaped initialData default then replaced it
wholesale with the raw /api/tools/agent-bridge/state response. The route returns
{ server, agents } but the UI reads { serverState, agentStates, bypassPatterns,
mappings }, so serverState became undefined and AgentBridgeServerCard crashed on
serverState.running — surfaced as the full-page 'Internal Server Error' boundary
(client render error, not a real 5xx).

Add a shared normalizeAgentBridgeState() that maps the route shape into the page
contract (server.running/certExists -> serverState) and always returns safe
defaults (never undefined serverState). Wired into both the SSR loader (page.tsx)
and the polling hook. The legacy 'agents' entry shape differs from AgentStateEntry
so it is not coerced; full route<->page contract reconciliation (port, upstreamCa,
bypassPatterns, mappings, agentStates) is a follow-up.

Co-authored-by: tycronk20 <tycronk20@users.noreply.github.com>

* docs: VS Code/Ollama endpoints + env & i18n tooling (#3319)

Integrated into release/v3.8.13 — VS Code/Ollama docs + env & i18n tooling

* feat(provider): test-all endpoint, rate-limit overrides, visibility f… (#3267)

Integrated into release/v3.8.13 — provider test-all endpoint, rate-limit overrides, model visibility

* feat: auto-combo optimization, playground model dropdown, only-configured toggle (#3322)

Integrated into release/v3.8.13 — auto-combo candidate expansion + playground dropdown + only-configured toggle

* feat(api): VS Code Copilot Ollama-compatible BYOK endpoint (#3316)

Integrated into release/v3.8.13 — VS Code Copilot Ollama-compatible BYOK endpoint (reconciled with #3306/#3309 auth hardening)

* chore(release): document #3320 in the v3.8.13 changelog + contributor credits

---------

Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com>
Co-authored-by: Wilson <pedbookmed@gmail.com>
Co-authored-by: Hernan Javier Ardila Sanchez <hjasgr@gmail.com>
Co-authored-by: Paijo <14921983+oyi77@users.noreply.github.com>
Co-authored-by: uniQta <uniQta@users.noreply.github.com>
Co-authored-by: onizukashonan14-png <onizukashonan14-png@users.noreply.github.com>
Co-authored-by: tycronk20 <tycronk20@users.noreply.github.com>
Co-authored-by: Vinayrnani <vinayrnani@gmail.com>
2026-06-06 19:13:11 -03:00
Diego Rodrigues de Sa e Souza
78454eed5e Merge pull request #3264 from diegosouzapw/release/v3.8.12
Release v3.8.12
v3.8.12
2026-06-06 08:09:11 -03:00
diegosouzapw
5bebf0e53c fix(quota,sse): clear SonarCloud new-reliability findings on the v3.8.12 diff
- chipotle/grokTls: explicit null checks instead of a Promise in a boolean
  conditional (behavior-preserving; clears the 2 MAJOR reliability bugs)
- sqliteQuotaStore.poolUsage: drop the unreachable dimMap scan loops (dimMap
  was never populated) — the lightweight snapshot already returns no
  dimensions; poolUsageWithDimensions() is the plan-aware path
- BudgetTab: presentation role + keyboard handler on the checkbox wrapper
2026-06-06 06:49:46 -03:00
diegosouzapw
7ab1ad85a1 chore(release): finalize v3.8.12 changelog + env-doc-sync + test drift 2026-06-06 06:14:57 -03:00
diegosouzapw
a8668ebd77 chore(governance): raise coverage gate 40 -> 60
test:coverage now enforces 60/60/60/60 (statements/lines/functions/branches);
real coverage is ~75-82% so this tightens the floor without new test work.
Updates the c8 --check-coverage thresholds in package.json and the matching
references in CLAUDE.md (Quick Start, testing table, Copilot policy, Hard
Rule #9). Salvaged from the never-pushed chore/skills-governance-tdd-vps
branch; the i18n CLAUDE.md mirrors carry a separate pre-existing drift and
are not gated by check-docs-sync.
2026-06-06 04:44:52 -03:00
diegosouzapw
27f6ea85f9 docs(changelog): add v3.8.12 entries for #3280/#3285/#3286/#3287
Quota Sharing Engine repair (#3280), MiniMax-M3 across 8 tiers (#3287),
emitHookBlocking payload chaining (#3286), Chipotle CodeQL hardening (#3285);
updated the contributors hall.
2026-06-06 04:28:38 -03:00
Paijo
1bc88d97ee fix(plugins): chain payload between emitHookBlocking handlers (#3286) (#3286)
Integrated into release/v3.8.12. Salvaged the emitHookBlocking payload-chaining fix from the now-closed plugins-v4 branch (#3221) and adapted it to the shipped release hooks.ts: each blocking handler now sees the body/metadata as mutated by previous handlers. TDD regression test included (RED before, GREEN after); existing plugins-hooks suites green (19+5), typecheck + lint clean.
2026-06-06 04:27:00 -03:00
Diego Rodrigues de Sa e Souza
3086894704 docs(readme): consolidate community at top (Discord + Telegram + WhatsApp) + promote Free-Token Budget section (#3289)
- Add the official Telegram group (t.me/omnirouteOficial) and gather Discord,
  Telegram and both WhatsApp groups into one community card block at the top;
  remove the scattered WhatsApp links from the nav line and the Support section
  (now a pointer to the top).
- Move the Free-Token Budget section from the bottom (before License) up to a
  hero section near the top, retitled '💰 ~1.9B Free Tokens / Month'.
2026-06-06 04:24:46 -03:00
Wilson
e1622ed88b feat(models): add MiniMax M3 across all provider tiers (#3110) (#3287)
Integrated into release/v3.8.12. Registers MiniMax-M3 (1M context, Anthropic-compatible) across 8 provider tiers (minimax, minimax-cn, opencode, opencode-go, opencode-zen, trae, ollama-cloud, nvidia). Validated: 8/8 new registry tests + 25 registry/model-catalog regression files green, typecheck + lint clean. Complements the #3141 max_tokens spec already on release.
2026-06-06 04:18:53 -03:00
Paijo
1344843a45 fix(security): use crypto.randomInt/randomUUID in chipotle + URL parser in test (#3285)
Integrated into release/v3.8.12. CodeQL hardening on the Chipotle executor: Math.random → crypto.randomInt/randomUUID, and a strict URL hostname check in the test. Fixed the node:crypto import (crypto.randomInt is not on the Web Crypto global → would crash at WS-connect) and added a regression guard exercising both helpers.
2026-06-06 04:16:51 -03:00
diegosouzapw
ba734b01b2 docs(changelog): credit @wilsonicdev for the Qoder 500-bypass diagnosis (#3282/#3247)
The #3247 fix shipped via #3283 (parallel session) 46s after @wilsonicdev
filed the same fix in #3282, leaving his PR stranded with no credit — the
#3242 credit-theft pattern. Repoint the entry to the merged #3283, credit
@wilsonicdev as co-author for the independent diagnosis, and note #3283
refined it to keep rejecting on an explicit-auth-signal 500.
2026-06-06 03:43:17 -03:00
Paijo
1c8f3bee97 fix(quota): resolve poolUsage dead code, burn rate, saturation signals, webhooks, and embeddings enforcement (#3280)
Integrated into release/v3.8.12. Quota Sharing Engine fixes: poolUsageWithDimensions promoted to the QuotaStore interface, single-snapshot burn rate, zero-weight normalization, Anthropic saturation signals, quota.exceeded webhook on block, and embeddings enforcement. Validated: 10/10 PR tests + 34 quota/embedding regression files green, typecheck + lint clean. Dropped the committed .omo/ agent-tooling artifacts.
2026-06-06 03:41:03 -03:00
Diego Rodrigues de Sa e Souza
7abb40c64c docs(free-tiers): richer budget-card image (28 models + first-month strip) + soften ToS framing to caution (#3284)
- Regenerate the README/dashboard mockup from the catalog: 28 pools in the grid
  (was 9), a balance-floored stacked bar (Mistral now ~40% of the bar, was ~90%),
  and a first-month signup-credit strip (~586M). Add the data-driven generator.
- FREE_TIERS.md: drop the alarming '🚫 Avoid / terms prohibit' framing — relabel
  those 19 providers as 'caution — worth checking', note their access is real and
  the OAuth/keyless ones aren't token-quantifiable (so out of the headline, not
  excluded as unusable).
2026-06-06 03:22:54 -03:00
Diego Rodrigues de Sa e Souza
a7e445edea fix(sse): don't mark a valid Qoder PAT expired on a generic Cosy 500 (#3247) (#3283)
A working Qoder PAT was reported as "expired". The validator probes the Cosy endpoint
(api1.qoder.sh) — which IS the correct PAT path (the executor falls back to it after the
expected 401 from api.qoder.com). The bug was the verdict: isCosyAppError (added by #2860)
marked ANY Cosy 500 with "success":false as an auth failure, including a generic
{..."msgCode":500,"message":"Internal Server Error"} server fault — contradicting the
older #1391 "5xx = valid bypass" rule.

Narrow it: a Cosy 500 only marks the PAT invalid when the body carries an EXPLICIT auth
signal (unauthorized/forbidden/expired/token invalid/...); a generic Internal Server Error
falls back to valid-bypass. #2860's protection for genuine auth rejections is preserved.

Regression test: tests/unit/qoder-cli.test.ts — the two pre-existing generic-500 cases now
assert valid:true (they encoded the #3247 bug) + a new explicit-auth-signal case asserts
valid:false. 13/13 green.
2026-06-06 03:11:58 -03:00
Diego Rodrigues de Sa e Souza
36932b62a7 fix(api): harden private webhook opt-in against cloud-metadata SSRF (#3269) (#3281)
Follow-up to the #3269 private-webhook opt-in. With the opt-in on, the private-host
check was bypassed entirely, leaving cloud-metadata endpoints (169.254.169.254,
metadata.google.internal, 100.100.100.200, link-local 169.254.0.0/16) reachable — the
classic SSRF -> IAM-credential pivot — and the webhook test endpoint returned the
upstream body, making it a content-exfiltration primitive against internal services.

- outboundUrlGuard: add isCloudMetadataHost(); parseAndValidateWebhookUrl blocks those
  hosts UNCONDITIONALLY, even when private targets are opted in.
- webhooks/[id]/test: redact responseBody for private targets (status + latency only).

Regression test: tests/unit/webhook-metadata-guard-3269.test.ts (RED before, GREEN after);
existing webhook SSRF/opt-in suites stay green (34/34).
2026-06-06 03:08:16 -03:00
Diego Rodrigues de Sa e Souza
a5d19bf4b9 fix(api): allow private webhook targets behind explicit opt-in (#3269) (#3279)
Webhooks hardcoded parseAndValidatePublicUrl, which blocks any RFC1918/loopback host —
breaking self-hosted setups that legitimately point webhooks at internal services
(n8n, Home Assistant, a LAN box). Provider URLs already had an opt-in
(OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS); webhooks now reuse it.

- outboundUrlGuard: add parseAndValidateWebhookUrl — gates the private-host check on
  arePrivateProviderUrlsAllowed() (default OFF); protocol + embedded-credential checks
  stay unconditional.
- swap all webhook call sites (create/update/test/validate-url + dispatcher x2) to it.

Regression test: tests/unit/webhook-private-optin-3269.test.ts (RED before, GREEN after);
existing webhook SSRF/dispatcher suites stay green (33/33).
2026-06-06 02:59:09 -03:00
diegosouzapw
a19cfd4036 docs(changelog): complete v3.8.12 audit — all 14 merged PRs + contributors hall
Audited every commit since v3.8.11 one-by-one. Added the missing v3.8.12
entries (features #3250/#3259/#3263/#3271, fixes #3248/#3249/#3261/#3256/#3274,
maintenance #3270), repointed the combo-rewrite and web-tools entries to their
actually-merged PRs (#3268, #3275) instead of the closed #3242/issue links, and
added the v3.8.12 Contributors hall. Also co-credited @ibanunmangun on the
v3.8.11 #3203 OAuth fix (independent first diagnosis via #3193).
2026-06-06 02:55:25 -03:00
Diego Rodrigues de Sa e Souza
e478ab23af fix(api): build /v1/images/edits multipart as Buffer, not global FormData (#3273) (#3278)
A custom OpenAI-compatible image-edit provider received an empty `model`. In production
`globalThis.fetch` is patched with node_modules/undici's fetch, whose `FormData` class
differs from `globalThis.FormData`; passing a native FormData made undici serialize it as
the string "[object FormData]" (text/plain), dropping every field including `model`.

handleOpenAIImageEdit now assembles the multipart body as a Buffer with an explicit
boundary + Content-Type, which every fetch impl accepts verbatim.

Regression test: tests/unit/image-edits-multipart-3273.test.ts reproduces the exact prod
condition (routes through undici's fetch) — RED before (upstream got text/plain
[object FormData]), GREEN after. Existing image suites stay green (50/50).
2026-06-06 02:52:44 -03:00
Diego Rodrigues de Sa e Souza
80c546eba9 fix(sse): strip reasoning_effort for non-reasoning Groq models (#3258) (#3277)
Regression of #764. Claude Code → Groq (llama-3.3-70b-versatile) returned HTTP 400
because the model was treated as reasoning-capable: supportsReasoning() defaulted to true,
so applyThinkingBudget did not strip reasoning params, and the claude→openai translator
forwarded reasoning_effort (and re-injected it from output_config.effort) — which Groq
rejects on non-reasoning models.

- providerRegistry: mark llama-3.3-70b-versatile + llama-4-scout supportsReasoning:false
  (gpt-oss / qwen3-32b keep reasoning — they accept reasoning_effort).
- stripThinkingConfig: also strip output_config.effort so the translator can't re-inject
  reasoning_effort downstream.

Regression test: tests/unit/thinking-budget-groq-3258.test.ts (RED before, GREEN after);
existing thinking-budget suites stay green (45/45).
2026-06-06 02:48:38 -03:00
Diego Rodrigues de Sa e Souza
41eb0091a2 fix(sse): parse <tool_call name=...> wrapper from web-cookie providers (#3260) (#3275)
ds-web/deepseek-v4-pro emits tool calls wrapped as
<tool_call name="skill">{"name":"customize-opencode"}</tool_call> instead of the
canonical <tool>{json}</tool>. webTools.ts only matched <tool>...</tool>, so the block
was silently dropped (and when arguments were present, the surrounding tag leaked into
content). Add TOOL_CALL_TAG_RE to capture the JSON body — the real tool name comes from
the body, never the tag's name= attribute — and extend the early-exit + range stripping.

Regression test: tests/unit/web-tools-translation-3260.test.ts (RED before, GREEN after).
Existing web-tools suites stay green (26/26).
2026-06-06 02:44:44 -03:00
Diego Rodrigues de Sa e Souza
30ebe0ae2e feat(free-tiers): per-model free-token budget + Monthly Budget dashboard card (#3263)
Free-token budget catalog + per-model budget + Monthly Budget dashboard card (joins #3257 + #3263 into one).

Integrated into release/v3.8.12.
2026-06-06 02:38:35 -03:00
Lenine Júnior
5d8f265192 feat(dashboard): bulk activate/deactivate/retest for selected provider connections (#3271)
Bulk activate/deactivate/retest for selected provider connections.

Integrated into release/v3.8.12. Thanks @leninejunior.
2026-06-06 02:33:17 -03:00
Felipe Almeman
6674f6a4f2 fix(db): detect SQLite driver-unavailable errors to avoid destructive rename (#3274)
Detect SQLite driver-unavailable errors to avoid destructive DB rename + optional FTS5 migration guard (split from #3073).

Integrated into release/v3.8.12. Thanks @zhiru.
2026-06-06 02:15:17 -03:00
Diego Rodrigues de Sa e Souza
6bfba384d8 fix(ci): deploy-vps recreates PM2 via bin + gates on /login 200 (#3270)
Synchronized deploy-vps hardening (PM2 recreate via bin + /api/monitoring/health gate + fail-on-unhealthy). Supersedes #3262.

Integrated into release/v3.8.12.
2026-06-06 02:11:21 -03:00
Diego Rodrigues de Sa e Souza
2ad2bcb13f fix(embeddings): block cross-dimension failover in embedding combos (#3256)
Block cross-dimension failover in embedding combos.

Integrated into release/v3.8.12.
2026-06-06 02:07:06 -03:00