Commit Graph

2221 Commits

Author SHA1 Message Date
Diego Rodrigues de Sa e Souza
2e7705debb fix(dashboard): restore the 8 bulk-import state declarations deleted by #6625 hook extraction (ReferenceError: bulkImportOpen — release E2E) 2026-07-13 06:51:20 -03:00
Diego Rodrigues de Sa e Souza
ffdc1282de fix(dashboard): restore poolLoaded/poolSaving state deleted by #6909 refactor (settings page runtime crash, caught by release E2E) 2026-07-13 06:07:31 -03:00
Diego Rodrigues de Sa e Souza
1c3cca399b fix(combo,ws): comboStickyRoundRobinLimit inherits instead of shadowing batched default; LiveWS standalone script boots again (#6678/#6072 follow-ups caught by release CI) 2026-07-13 03:35:35 -03:00
Diego Rodrigues de Sa e Souza
4478f5f71d chore(base): backfill #6909 i18n keys (en+pt-BR) and align gemini defaults test with #6943 (unit-full pre-flight) 2026-07-13 00:28:12 -03:00
Diego Rodrigues de Sa e Souza
9b43a00b60 fix(combos): show embedding/rerank models and disambiguate duplicate names in builder options (#6975, #6957) (#6991)
Removes the leftover chat-only isChatCapable gate from addModelOption() (#6975) and adds a name-disambiguation pass at the end of buildModelOptions() so distinct model ids sharing the same upstream display name fall back to their id (#6957). Both proven with TDD repro tests (RED->GREEN).
2026-07-12 18:07:58 -03:00
Diego Rodrigues de Sa e Souza
271bf52da1 chore(base): fix 2 mechanical release-tip base-reds (relayProbeStats re-export + OMNI_MAX_CONCURRENT_CONNECTIONS docs) 2026-07-12 18:07:20 -03:00
Paijo
b4c47f5cbf feat(sse): add connection backpressure for chat handler (#6590)
Add checkConnectionCapacity guard with 429 + Retry-After in handleChat().
Introduce OMNI_MAX_CONCURRENT_CONNECTIONS env-bound cap, disabled (0) by
default so existing deployments are unaffected until an operator opts in.

Reconstructed from PR #6590, isolating only the backpressure change —
the original branch also carried unrelated headroom/docker/perf work
from the author's separate #6572 branch.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-12 10:50:27 -03:00
Paijo
a61a4dc673 fix: eliminate redundant getApiKeyMetadata call in embeddings route (#6929)
enforceApiKeyPolicy() already fetches the API key metadata and returns
it as policy.apiKeyInfo. The old code at line 72 called getApiKeyMetadata
a third time per request (third hash+DB query after isValidApiKey and
enforceApiKeyPolicy's internal fetch).

Change: use policy.apiKeyInfo directly instead of re-querying. Also
removes the now-unused getApiKeyMetadata import.

Adds a regression test exercising the dashboard-playground-key path
(no bearer token, only enforceApiKeyPolicy's resolvePlaygroundTestKey
fallback resolves the key) — the old apiKeyRaw-gated call always
produced a null apiKeyMeta on that path, while policy.apiKeyInfo
correctly carries it through to the downstream call log.

Split out of the original PR: dropped the unrelated 46-provider-icon
commit that had been bundled onto the same branch.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-12 10:33:33 -03:00
Paijo
66cb93f9bd perf: thread pre-fetched token to checkRateLimit avoiding re-query (#6930)
* perf: thread pre-fetched token to checkRateLimit avoiding re-query

getRelayTokenByHash already fetches the full RelayToken row. A few
lines later checkRateLimit(token.id) does a second SELECT * FROM
relay_tokens on a different predicate (id instead of token_hash).

Change:
- checkRateLimit accepts an optional existingToken parameter; when
  provided, skips the re-query entirely.
- Both relay routes (chat completions + bifrost) pass the already-
  fetched token.
- The function now uses RelayToken (camelCase) instead of RelayTokenRow
  (snake_case) when the token is passed in.

PR-URL: fix-relay-thread-token

* test(db): add regression coverage for checkRateLimit existingToken fast-path

Adds node:test coverage for src/lib/db/relayProxies.ts::checkRateLimit
proving the existingToken fast-path (pre-fetched RelayToken threaded in,
no re-query) agrees with the legacy re-query path (no token passed),
and that the per-minute cap is still enforced through the fast-path.
Also adds a changelog.d fragment for the perf fix in 9d4cd90e7.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-12 10:30:26 -03:00
Paijo
084fca42bf fix(tokenHealthCheck): case-sensitive provider comparisons break rotating/gh checks (#6947)
ROTATING_REFRESH_PROVIDERS.has(conn.provider) fails for 'OpenAI' or 'Github'
- the set is all lowercase. Same issue for the GitHub Copilot sub-token
refresh guard. Both now normalize to lowercase before comparison, matching
the established pattern from getHealthCheckSkipProviders() (line 201) and
isGitHubAccessTokenOnlyConnection() (line 94).

Replaces the whole-file regex assertion in oauth-providers-error-handling
(which passed even on unfixed code) with two statement-scoped regression
tests that fail against origin/release/v3.8.47's unfixed source and pass
only once both call sites are normalized.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-12 10:29:48 -03:00
Paijo
19d1a5d391 fix(db): add authType filter support to getProviderConnections (#6946)
getProviderConnections ignored the authType query param, causing
callers like tokenHealthCheck.ts and /api/token-health to fetch and
decrypt every connection instead of only the OAuth ones they asked
for. Add the missing auth_type WHERE clause and a regression test.

Rebased to drop the unrelated 46-icon commit (duplicate of #6926)
and the accidentally-committed tests/unit/authz/__stub_apiKeys.mjs
runtime artifact; replaced with a real unit test asserting the
authType filter excludes non-matching connections.

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-12 10:27:42 -03:00
Diego Rodrigues de Sa e Souza
c8f116d806 fix(api): use local-first SSRF guard for LAN model-list discovery (#6939) (#6966) 2026-07-12 10:24:01 -03:00
Diego Rodrigues de Sa e Souza
c1fc661c90 fix(sse): classify LAN embeddings providers as no-auth (#6925) (#6962)
Private/LAN embeddings provider_nodes (10.0.0.0/8, 192.168.0.0/16,
100.64.0.0/10 CGNAT) were excluded by a hand-rolled hostname filter that
only matched localhost/127.0.0.1/172.16-31, forcing them through the
apikey/bearer credential fallback and returning 401 for keyless local
providers like a LAN Ollama instance.

Reuse the shared isPrivateHost()/isCloudMetadataHost() classification from
outboundUrlGuard.ts in both the dynamic-provider filter and the
provider_node fallback branch, so any private host resolves to
authType 'none' while cloud-metadata endpoints stay blocked.
2026-07-12 10:23:54 -03:00
Diego Rodrigues de Sa e Souza
152d77cf4b fix(dashboard): label audio/embeddings/image compatible providers by kind on ProviderCard (#6936) (#6961)
ProviderCard's compatibility badge used a binary apiType ternary
(responses vs everything-else -> "Chat"), so audio-transcriptions,
audio-speech, images-generations and embeddings compatible providers
(e.g. a locally-hosted speaches TTS/STT server) were mislabeled as
"Chat". Reuse the existing KIND_LABEL map (stt/tts/image/embedding)
instead of adding new i18n keys.
2026-07-12 10:23:47 -03:00
Paijo
8017f4127f feat: add icons for 46 missing provider images (#6926)
* feat: add icons for 46 missing provider images

- Add SVG icons for 46 providers missing brand images
- Add 3 LOBE aliases (bai, clinepass, copilot-m365-web)
- Register all new SVGs in KNOWN_SVGS lookup

New SVG icons cover: api-airforce, auggie, bluesminds, byteplus,
bytez, charm-hyper, chipotle, chutes, crof, dgrid, digitalocean,
dit, duckduckgo-web, factory, freeaiapikey, freemodel-dev, galadriel,
gitlawb, gitlawb-gmi, hackclub, haiper, hcnsec, ideogram, kenari,
leonardo, llm7, modelscope, nube, openadapter, orcarouter, pioneer,
publicai, qiniu, requesty, sumopod, t3-web, theoldllm, tokenrouter,
uncloseai, veoaifree-web, wafer, x5lab, yuanbao-web, zed-hosted,
zenmux, zenmux-free

* fix(icons): restore accidentally-deleted cohere alias in LOBE_PROVIDER_ALIASES

The 46-icon addition dropped the existing `cohere: "Cohere"` entry; restore it
alphabetically between codex-cloud and comfyui.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-12 10:22:04 -03:00
Paijo
10cb2447b1 [trim] feat(combo): add context requirements config for target filtering (#6907)
* feat(combo): add context requirements config for target filtering

Add contextRequirements config field to combo runtime config:
- minContextWindow: filter models below threshold (0-10M tokens)
- preferLargeContext: sort targets by context size descending
- contextFilterMode: 'strict' excludes unknown limits, 'lenient' includes them

Implementation:
- Added Zod schema validation in combo.ts
- Created contextRequirements.ts module with applyContextRequirements()
- Integrated filtering after filterTargetsByRequestCompatibility()
- Full test coverage with unit + integration tests

Tests: 17/17 pass (combo-context-requirements.test.ts + integration)

* feat(combo): add ContextRequirementsEditor UI component

Add standalone React component for editing context requirements config:
- Slider for minContextWindow (0 to 1M tokens) with presets
- Toggle for preferLargeContext sorting
- Radio group for contextFilterMode (strict/lenient)
- Tooltips explaining each option
- Active filters summary display

Component features:
- Shadcn UI components (Card, Slider, Switch, RadioGroup)
- Preset buttons for common context sizes (8K, 32K, 128K, 1M)
- Conditional display of filter mode when minContextWindow > 0
- Clear visual feedback of active filters

Integration:
Import and use in combo config form where other config fields
like fusionTuning and judgeModel are edited. Pass combo.config.contextRequirements
as value prop and update on onChange.

Example usage:
<ContextRequirementsEditor
  value={config.contextRequirements}
  onChange={(val) => updateConfig({ contextRequirements: val })}
/>

UI matches existing combo config editor patterns.

* feat(combo): wire ContextRequirementsEditor into combo config form

Adds context requirements section to combo edit page (strategy section),
matching existing ResponseValidation pattern. Placed after response
validation block, before agent features.

* docs(combo): add context requirements feature documentation

Covers: config schema, behavior, use cases, UI integration,
troubleshooting, and test instructions.

* fix(combo): pass provider+modelStr to getModelContextLimit for accurate context resolution

Per gemini-code-assist review feedback: model names are not globally
unique across providers. Passing both provider and modelStr ensures
correct context limit resolution in applyContextRequirements().

* fix(combo): repair broken doc links and restore test:unit:fast flag

- Point docs/combo-context-requirements.md 'Related' links at real docs
  (routing/AUTO-COMBO.md, architecture/RESILIENCE_GUIDE.md) — the three
  placeholder links (strategies.md/model-capabilities.md/fusion-tuning.md)
  did not exist and failed check:doc-links (Docs Gates fast-path).
- Revert an out-of-scope package.json change to test:unit:fast that dropped
  --test-isolation=none; restore to match release/v3.8.47.

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

* test(combo): validate context requirements against the real Zod schema

Point tests/unit/combo-context-requirements.test.ts at the real
comboRuntimeConfigSchema export (src/shared/validation/schemas/combo.ts)
instead of hand-duplicating the Zod schema inline, so the test catches
schema drift.

Also declare contextRequirements on DEFAULT_COMBO_CONFIG so
resolveComboSetupConfig's inferred return type includes the key —
combo.ts reads config.contextRequirements but the property was missing
from the object typecheck:core infers types from, causing a build error.

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

* fix(combos): remove dead ContextRequirementsEditor scaffolding (broken ui/card+label imports)

The editor imported @/components/ui/card and @/components/ui/label which do not
exist in the repo, breaking the Turbopack build. Removed the editor + its page.tsx
usage + doc mention; the real fix (comboConfig contextRequirements default + test)
is preserved.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
2026-07-12 03:41:50 -03:00
backryun
67a0b99240 feat(providers): add GPT-5.6 model family (#6862)
* feat(providers): add GPT-5.6 model family

* fix(chatgpt-web): resume temporary chat handoffs

* fix(codex): auto-merge discovery, filter denylist, revalidate on lifecycle

Restore live/GitHub auto-merge for Codex catalogs, drop models via
explicit denylist (GPT-5.4 family), and run scrub+live re-sync once on
first-start, app upgrade, or setup completion. Success log:
kill deprecated models complete.

* fix(codex): preserve live catalog reconciliation

Expose remote-only Codex models without dropping user custom entries, and complete lifecycle revalidation only after a successful internal sync. Keep credentialed self-fetches pinned to the active dashboard listener.

---------

Co-authored-by: backryun <backryun@daonlab.local>
2026-07-12 03:30:47 -03:00
Paijo
b5e75bb8fe fix(proxy): relay repair + free-pool UX + relay awareness (#6909)
* feat(proxy): relay repair + free-pool UX + relay awareness

* fix(proxy): preserve existing notes fields on relay repair; fix cpu limit /1000 across all 5 container providers

* feat(proxy): extract bulk-import and pool-modal hooks (#6625)

* fix: prevent relay type normalization to http on PATCH

Bug: updateProxyRegistrySchema inherited .default("http") from the base
schema, causing PATCH to silently overwrite relay types (vercel/deno/cloudflare)
with "http" when the client didn't send a type field.

- Move .default('http') from proxyRegistryFieldsSchema to
  createProxyRegistrySchema (only applies to new proxies)
- Strip undefined keys from validated changes before passing to
  updateProxy — .partial() leaves absent fields as undefined, which
  the spread merge in updateProxyRow would propagate to the DB
- Add console.warn in extractRelayAuth when decrypt fails on a
  known-encrypted relayAuthEnc blob

Closes #6905

* feat: replace Load More with page-number pagination in FreePoolTab

- Adds page-number pagination controls with prev/next buttons
- Shows per-page summary with total counts
- Resets to page 1 on filter change via wrapper setters

* fix(proxy): restore free-proxy sync-error tracking reverted by pagination commit

commit 2c8e79f13 (page-number pagination for FreePoolTab) accidentally
reverted the recordFreeProxySyncErrors/clearFreeProxySyncErrors/
getFreeProxySyncErrors functions and the search/sortBy list options that
an earlier commit (6f9ce75f3) in this same PR had added to
src/lib/db/freeProxies.ts and src/app/api/settings/free-proxies/route.ts.

localDb.ts still re-exported the three sync-error functions, so every
module that transitively imports it (which is most of the unit test
suite, plus the Next.js build used by dast-smoke) failed at load time
with "The requested module './db/freeProxies' does not provide an
export named 'clearFreeProxySyncErrors'".

Restores the reverted implementation (verbatim) and fixes the two new
"requires management auth" tests, which asserted 401 for an
unauthenticated request without configuring INITIAL_PASSWORD +
requireLogin first — on a fresh DB with no password configured,
isAuthRequired() treats a loopback request as the pre-setup bootstrap
path and allows it through, so the assertion needs the same
password/requireLogin setup already used by
tests/unit/api/settings-audit.test.ts.

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

* fix(proxy): trim unrelated scope from relay-repair/free-pool PR

Remove two subsystems that are unrelated to relay repair and the
free-pool UX and were never wired into the app:

- open-sse/services/combo/capabilityRequirements.ts and
  CapabilityRequirementsEditor.tsx: a combo capability-filtering
  feature never imported by combo.ts or combos/page.tsx, with no
  test coverage.
- src/lib/skills/containerProvider.ts CPU-limit rescale: an
  untested change to sandbox resource limits, unrelated to the
  proxy/relay subsystem this PR targets. Restored to the
  release baseline.

Also renumber the free_proxy_sync_errors migration 121 -> 122 to
avoid colliding with #6855, which independently claims 121 on the
same release branch.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-12 02:28:26 -03:00
Diego Rodrigues de Sa e Souza
df3a6cf674 fix(providers): route AgentRouter key validation through CC wire image (#6377) (#6882)
* fix(providers): route AgentRouter key validation through CC wire image (#6377)

* test(6377): type fetch mock to satisfy no-explicit-any gate
2026-07-12 02:00:19 -03:00
Diego Rodrigues de Sa e Souza
858598a200 fix(db): stop legacy log-archive migration from deleting the live app-logger directory and crashing startup on a stat/stream race (#6401) (#6898)
archiveLegacyRequestLogs() swept the entire DATA_DIR/logs directory as a
single "legacy" target and recursively deleted it after zipping. Since
PR #6234 moved the default app-log path to DATA_DIR/logs/application,
the migration was deleting the live file logger's own directory on
every boot until its marker file existed (#6799).

Separately, yazl's addFile() does an internal stat-then-stream read; if
a target file grows between those two steps (e.g. an actively-written
log), yazl emits "error" directly on the ZipFile instance. That event
had no listener, so Node re-threw it as an uncaughtException that
crashed the whole process at startup (#6401) — misdiagnosed upstream as
Turbopack/Windows chunk corruption because the stack trace pointed into
a bundled chunk.

Fix:
- listArchiveTargets() now enumerates DATA_DIR/logs entries individually
  and skips the live app-logger directory (resolved via
  logEnv.getAppLogFilePath()), so the shared parent directory is never
  deleted wholesale.
- createLegacyArchive() wires a zipFile.on("error", ...) handler so a
  stat/stream race rejects the promise (caught by the existing
  try/catch) instead of escaping as an uncaughtException.

Regression test: tests/unit/usage-migrations-legacy-archive-safety.test.ts
(RED on unfixed code, GREEN after fix). Updated
tests/unit/request-log-migration.test.ts to the corrected contract —
DATA_DIR/logs itself now survives the archive sweep.

Gates run clean: file-size, complexity, cognitive-complexity,
changelog-integrity, typecheck:core, eslint (suppressions), and the
existing usage-migrations/request-log-migration unit suites.
2026-07-12 02:00:02 -03:00
Diego Rodrigues de Sa e Souza
a6dfd1068e fix(providers): wire devin cloud-agent into provider validation and static models (#6142) (#6894) 2026-07-12 01:59:53 -03:00
Diego Rodrigues de Sa e Souza
8c4364a597 fix(providers): give v0-vercel-web its own alias so credentials are detected (#6343) (#6891)
* fix(providers): give v0-vercel-web its own alias so credentials are detected (#6343)

* test(6343): type casts to satisfy no-explicit-any gate

* test(6343): register v0-web + cliproxyapi tests in stryker tap.testFiles

The two unit tests added on this branch cover mutated modules
(src/sse/services/auth.ts, comboContextCache.ts) but were missing from
stryker.conf.json tap.testFiles, tripping check:mutation-test-coverage --strict.

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
2026-07-12 01:59:44 -03:00
Diego Rodrigues de Sa e Souza
0834bb2c70 fix(providers): strip redundant node prefix on connId-addressed custom models (#6772) (#6890) 2026-07-12 01:59:40 -03:00
Chirag Singhal
5097e3a111 fix(api): route error responses through sanitizeErrorMessage (Hard Rule #12) (#6886)
* fix(api): route error responses through sanitizeErrorMessage (Hard Rule #12)

9 API routes returned raw String(error)/error.message directly in HTTP 500
bodies, leaking SQLite paths, SQL text and internal messages. Route all through
sanitizeErrorMessage() per Hard Rule #12:

- settings/compression (GET+PUT), settings/compression/mcp-accessibility (GET+PUT)
- cache/entries (GET+POST), db/health (GET+POST), db-backups/exportAll
- assess, combos/test, settings/notion, settings/obsidian

Test: tests/unit/rule12-error-sanitization-sweep.test.ts asserts sanitized 500
bodies contain no absolute paths / stack tails.

* test(stryker): register rule12 error-sanitization sweep in tap.testFiles

The new tests/unit/rule12-error-sanitization-sweep.test.ts covers a mutated
module, so it must be listed in stryker.conf.json tap.testFiles for the
mutation-coverage gate (check-mutation-test-coverage.mjs --strict) to pass.

Co-authored-by: Chirag Singhal <chirag127@users.noreply.github.com>

---------

Co-authored-by: Chirag Singhal <chirag127@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
2026-07-12 01:59:31 -03:00
growab
c4c8af3965 feat(proxy): shorthand proxy formats + protocol header mode for bulk import (#6867)
* fix(electron): bump electron 42→43 + build better-sqlite3 from source (ABI 148) (#6605)

fix(electron): bump electron 42→43 + rebuild better-sqlite3 from source against the Electron ABI (148).

Electron 43 raises NODE_MODULE_VERSION to 148; better-sqlite3@12.11.1 has no electron-v148 prebuild, so the packaged app died with 'Nenhum driver SQLite disponível'. prepare-electron-standalone now compiles better-sqlite3 from source against the electron headers into build/Release (where 'bindings' resolves it). Validated by Electron Package Smoke (green) + local (node_register_module_v148).

Supersedes #6378. (--admin: the only reds are SonarQube/SonarCloud failing on a coverage-report artifact digest-mismatch — a GitHub Actions infra flake, not this diff; Sonar is green on main and the diff touches only the electron build.)

* deps: bump the development group across 1 directory with 6 updates (#6588)

deps: bump the development group (6 updates). Rebased onto current main; all checks green after the electron-smoke fix (#6605).

* fix(proxy): force CONNECT tunnel for HTTP proxied requests (undici 8.7) + production deps bump (#6620)

fix(proxy): force CONNECT tunnel for HTTP proxied requests (undici 8.7) + production deps bump.

undici 8.6+ changed ProxyAgent to forward plain-HTTP via request-proxy instead of CONNECT, breaking OAuth refresh through a connection proxy (501). proxyDispatcher now passes proxyTunnel:true. Validated: Unit Tests 3/8 (the OAuth-proxy test) green, new regression test green (fails without the fix on undici 8.7), SonarQube green.

Supersedes #6380. (--admin: the only red is Electron Package Smoke failing on a next-build artifact 'digest-mismatch' — a GitHub Actions infra flake corrupting the asar ('file data stream has unexpected number of bytes'); the better-sqlite3 rebuild itself succeeded (gyp ok) and the electron path is unchanged from #6605 which passed the smoke. Not this diff.)

* feat(proxy): add shorthand formats + protocol header mode for bulk import

Supports 6 new shorthand formats alongside the existing pipe-delimited
parser:
  - ip:port
  - ip:port:user:pass
  - user:pass@ip:port
  - user:pass:ip:port
  - protocol://ip:port
  - protocol://user:pass@ip:port

Protocol header mode: a bare protocol name (http/https/socks5) on its
own line sets the default type for subsequent protocol-less shorthand
lines. Explicit protocol:// prefix always takes precedence over the
header default.

Changes:
- Rewrite parseBulkProxyImport.ts with parseShorthandLine helper
- Use Record<string, true> for static lookup tables (VALID_PROXY_TYPES,
  VALID_PROXY_STATUSES) per project convention
- Add looksLikeHost() heuristic to disambiguate 4-colon format
  (ip:port:user:pass vs user:pass:ip:port)
- Update BULK_IMPORT_TEMPLATE in ProxyRegistryManager.tsx with full
  documentation and examples for all formats
- Update en.json bulkImportDescription to list all supported formats
- Add 30 unit tests covering every format, edge cases, and regressions
  for the existing pipe-delimited path

---------

Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
2026-07-12 01:59:03 -03:00
Imam Wahyu Widodo
6530c92aa6 feat(provider): add OpenVecta AI inference gateway (#6833)
* fix(electron): bump electron 42→43 + build better-sqlite3 from source (ABI 148) (#6605)

fix(electron): bump electron 42→43 + rebuild better-sqlite3 from source against the Electron ABI (148).

Electron 43 raises NODE_MODULE_VERSION to 148; better-sqlite3@12.11.1 has no electron-v148 prebuild, so the packaged app died with 'Nenhum driver SQLite disponível'. prepare-electron-standalone now compiles better-sqlite3 from source against the electron headers into build/Release (where 'bindings' resolves it). Validated by Electron Package Smoke (green) + local (node_register_module_v148).

Supersedes #6378. (--admin: the only reds are SonarQube/SonarCloud failing on a coverage-report artifact digest-mismatch — a GitHub Actions infra flake, not this diff; Sonar is green on main and the diff touches only the electron build.)

* deps: bump the development group across 1 directory with 6 updates (#6588)

deps: bump the development group (6 updates). Rebased onto current main; all checks green after the electron-smoke fix (#6605).

* fix(proxy): force CONNECT tunnel for HTTP proxied requests (undici 8.7) + production deps bump (#6620)

fix(proxy): force CONNECT tunnel for HTTP proxied requests (undici 8.7) + production deps bump.

undici 8.6+ changed ProxyAgent to forward plain-HTTP via request-proxy instead of CONNECT, breaking OAuth refresh through a connection proxy (501). proxyDispatcher now passes proxyTunnel:true. Validated: Unit Tests 3/8 (the OAuth-proxy test) green, new regression test green (fails without the fix on undici 8.7), SonarQube green.

Supersedes #6380. (--admin: the only red is Electron Package Smoke failing on a next-build artifact 'digest-mismatch' — a GitHub Actions infra flake corrupting the asar ('file data stream has unexpected number of bytes'); the better-sqlite3 rebuild itself succeeded (gyp ok) and the electron path is unchanged from #6605 which passed the smoke. Not this diff.)

* feat(provider): add OpenVecta AI inference gateway

OpenVecta (https://openvecta.com/) is an OpenAI-compatible AI inference
gateway hosting LLMs (GLM, Claude, DeepSeek, GPT OSS, Llama, Kimi,
Nemotron...) plus text-embedding-* models behind a single Bearer key.

Wiring (7 integration points):
- src/shared/constants/providers/apikey/inference-hosts.ts: catalog entry
- open-sse/config/providers/registry/openvecta/index.ts: registry w/ 9 seed LLMs
- open-sse/config/providers/index.ts: wire into REGISTRY
- src/app/api/providers/[id]/models/discovery/providerModelsConfig.ts: live /v1/models URL
- src/app/api/providers/[id]/models/discovery/providerSets.ts: NAMED_OPENAI_STYLE_PROVIDERS
- public/providers/openvecta.svg: brand icon
- tests/unit/openvecta-provider-registration.test.ts: regression guard (6 tests, all pass)

No executor needed — buildOpenAiCompatibleRegistryEntry wires
format=openai / executor=default / authType=apikey / authHeader=bearer.

Live catalog discovery uses the existing NAMED_OPENAI_STYLE_PROVIDERS
path (live /v1/models fetch + registry seed as offline fallback).

Validation:
- npm run typecheck:core         clean
- npm run typecheck:noimplicit:core 4 errors in unchanged files (combo.ts, cliRuntime.ts); 0 in new code
- npm run lint                    clean
- node --import tsx/esm --test tests/unit/openvecta-provider-registration.test.ts   6/6 pass
- sibling tests/unit/openai-style-providers-4239-4155-3841.test.ts  18/18 pass (no regression)

* chore(merge): drop unrelated main-drift from PR fork + fix count/golden drift

The fork branch predated main's electron 42→43 bump (#6605) and several other
package.json/lockfile churn; those files are unrelated to the OpenVecta
provider addition and were reintroducing an older/stale state (version
3.8.46, electron 42, older bun/eslint-config-next) that broke the Electron
Package Smoke check. Restored package.json, package-lock.json,
electron/package.json, electron/package-lock.json, and
scripts/build/prepare-electron-standalone.mjs to match
origin/release/v3.8.47.

Also updates the two provider-count assertions (166->167) and regenerates
the translate-path golden snapshot to account for the new openvecta entry.

Co-authored-by: hajilok <120608486+hajilok@users.noreply.github.com>

---------

Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
2026-07-12 01:58:53 -03:00
Chirag Singhal
6973e2bd34 fix(api): return 400 (not 500) on malformed JSON body (#6871)
Co-authored-by: Chirag Singhal <chirag127@users.noreply.github.com>
2026-07-11 21:36:33 -03:00
MikeTuev
14c182ff37 fix(dashboard): logs detail modal no longer reopens on first close (#6830)
LogsPage recomputed initialId from window.location on every render, but the
App Router syncs window.location only after the navigation commits. Closing
the detail modal re-rendered the page while the URL still carried ?id=X, so
initialSelectedId flipped null -> X and the child's one-shot deep-link effect
(guard still unarmed after the open-click render, where location was stale in
the other direction) reopened the modal. Only the second close worked.

Read the id once via lazy useState so the prop stays stable for the page's
lifetime; deep links still open the modal on mount.

Regression test reproduces the App Router ordering with a router.replace mock
that re-renders the page before committing the URL.
2026-07-11 21:36:25 -03:00
Diego Rodrigues de Sa e Souza
adb1fc5b27 fix(providers): honor max_token capability override in reasoning buffer clamp (#6524) (#6904)
getExplicitModelOutputCap() (the clamp ceiling used by
resolveReasoningBufferedMaxTokens) only ever read the unvalidated synced
limit_output / registry / static-spec chain — it ignored the operator-settable
max_token capability override that getResolvedModelCapabilities() already
consulted. When a provider's synced catalog row reports a wrong limit_output
(e.g. ollama-cloud/deepseek-v4-flash: limit_output=1048576, same as
limit_context, while the real upstream cap is 65536), the reasoning-buffer
clamp trusted the bad number and inflated max_tokens 64000 -> 96000, which
upstream rejected with "exceeds model's maximum output tokens (65536)".

The override table (model_capability_overrides, "max_token" key,
/api/model-capability-overrides) is the existing, already-shipped remediation
path for exactly this class of bad catalog data, but reasoningTokenBuffer.ts
had no way to benefit from it. Extracted the override lookup into a shared
getMaxTokenCapabilityOverride() helper and made getExplicitModelOutputCap()
consult it first, so both read paths now agree.
2026-07-11 11:22:15 -03:00
Diego Rodrigues de Sa e Souza
ec553dd9c0 fix(db): share sql.js preinit across callers, fix named-param bind (#6628, #6802) (#6899)
- preInitSqlJs() now memoizes an in-flight Promise (not just the resolved
  adapter) per filePath, so concurrent BATCH/STARTUP/HealthCheck/
  ProviderLimitsSync callers at boot share one full-file read+WASM decode
  instead of each independently reloading the whole database — the
  thundering-herd amplifier of the OOM condition #6632 already partly
  fixed, left un-implemented by the reporter's own proposed fix (#6628).

- sqljsAdapter's run/get/all now unwrap a lone named-parameter object
  (e.g. .all({ isActive: 1 }) for "WHERE is_active = @isActive", the same
  call shape getProviderConnections() already uses against better-sqlite3)
  before calling sql.js's stmt.bind(), expanding it to the @/:/$ sigil
  variants sql.js's own named-bind path requires. Previously the object
  was wrapped into an array and sql.js took the positional-bind path,
  throwing "Wrong API use : tried to bind a value of an unknown type
  ([object Object])." whenever the sql.js WASM fallback driver was active
  — exactly the error #6802 reported (misattributed to better-sqlite3).

Regression tests added to tests/unit/db-adapters/driverFactory.test.ts and
tests/unit/db-adapters/sqljsAdapter.test.ts, both proven RED against the
prior code and GREEN after the fix.
2026-07-11 11:21:37 -03:00
Diego Rodrigues de Sa e Souza
ac81235609 fix(dashboard): surface Claude extraUsage credits in quota card (#6806) (#6896)
Enterprise-tier Claude accounts (default_raven_enterprise) don't get
five_hour/seven_day utilization windows from Anthropic's OAuth usage
endpoint — only an extra_usage credit-billing block. parseClaude()
only read data.quotas, so quotas stayed {} and the dashboard showed
"No quota data" even when extraUsage showed the account 100%
exhausted. parseClaude() now folds an enabled extraUsage block into a
credits-style quota row (mirroring parseCodex's bankedResetCredits
pattern), both when quotas is empty and when it's already populated.
2026-07-11 11:21:30 -03:00
Diego Rodrigues de Sa e Souza
69e47cdec5 fix(providers): honor a provider-level proxy assigned to no-auth providers (#6272) (#6895)
No-auth providers (mimocode, opencode, ...) are always dispatched with a single
hardcoded connectionId ("noauth" — SYNTHETIC_NOAUTH_CONNECTION_ID in
src/sse/services/auth.ts). No provider_connections row ever has id="noauth", so
resolveProxyForConnection() in src/lib/db/settings.ts could never populate
connectionRecord for them, and its provider-level proxy lookup (Steps 6/8) only
runs when connectionRecord is present. A proxy assigned via Settings -> Providers
-> mimocode was therefore silently ignored, reproducing the reporter's "same
thing happen when i set the proxy directly in the provider menu" symptom.

Adds a best-effort fallback (src/lib/db/settings/noAuthProxyFallback.ts): when
connectionRecord could not be resolved, scan the known no-auth provider ids for a
configured provider-level proxy (registry first, then legacy) before falling
through to the global/direct steps.

Regression test: tests/unit/proxy-noauth-provider-6272.test.ts (RED on unfixed
code — resolved to level=direct/proxy=null; GREEN after the fix).
2026-07-11 11:21:22 -03:00
Diego Rodrigues de Sa e Souza
8f90618308 feat: add Z.ai Web free web-cookie provider (#4056) (#6823)
* feat(providers): add Z.ai Web free web-cookie provider (#4056)

New zai-web web-session provider drives the free chat.z.ai consumer
chat UI via a pasted browser cookie, distinct from the existing
API-key zai/glm/glm-cn/glmt providers (api.z.ai). ZaiWebExecutor posts
to chat.z.ai/api/chat/completions with the cookie forwarded both as
Cookie and Authorization: Bearer <token>, and normalizes both z.ai's
internal delta_content/phase SSE envelope and a pass-through
OpenAI-shaped choices[].delta frame into standard chat-completion
chunks.

Registered in WEB_COOKIE_PROVIDERS, WEB_SESSION_CREDENTIAL_REQUIREMENTS,
the provider registry (GLM-4.6/4.5/4.5V models), the executor factory,
and tokenExtractionConfig.ts for in-app cookie capture.

* fix(providers): regenerate translate-path golden for zai-web + reduce cognitive complexity

* fix(providers): rename ZaiWebExecutor.buildHeaders to avoid incompatible BaseExecutor override

* chore(merge): re-sync with release/v3.8.47; move changelog bullet to changelog.d fragment (merge-storm proof)
2026-07-11 07:39:39 -03:00
Diego Rodrigues de Sa e Souza
d838be8df8 feat(usage): surface Antigravity weekly quota alongside the 5-hour window (#4017) (#6818)
* feat(usage): surface Antigravity weekly quota alongside the 5-hour window (#4017)

Antigravity enforces both a 5-hour and a weekly usage limit, but the agy/antigravity
quota widget only exposed the 5-hour window. The weekly limit isn't in the per-model
retrieveUserQuota response already fetched — it lives in a separate, undocumented
retrieveUserQuotaSummary RPC that groups models into families (Gemini Models, Claude
and GPT models) with one weekly bucket per family.

Adds a self-contained usage/antigravityWeeklyQuota.ts leaf: a cached, best-effort
fetch of that RPC + a pure parser that extracts the weekly-labeled bucket per group
(window inferred from bucketId/displayName text, matching the reverse-engineered
shape documented by third-party Antigravity clients) into gemini_weekly/
claude_gpt_weekly quota entries, merged into the existing quotas map the widget
already renders generically. A failed/unavailable RPC never affects the existing
per-model quotas.

Live VPS validation attempt (192.168.0.15, real antigravity account): both
retrieveUserQuota and retrieveUserQuotaSummary currently return 429
RESOURCE_EXHAUSTED for that account, so the live response shape could not be
captured directly. The parser was instead validated via TDD against the bucket
shape documented by CodexBar (steipete/CodexBar), a third-party Antigravity client
that reverse-engineered the same RPC, and is defensive against both response
envelopes it has observed (top-level groups[] and nested quotaSummary.groups[]).

* chore(merge): re-sync with release/v3.8.47 (restore CHANGELOG, keep own bullet)

* chore(merge): re-sync with release/v3.8.47; move changelog bullet to changelog.d fragment (merge-storm proof)
2026-07-11 07:39:24 -03:00
Jan Leon
d242e225de Discover live Codex models (#6776)
* Add live model discovery for provider catalog

* Fix model discovery request headers

* fix(codex): sync live model limits with local catalog

* test(codex): split live model discovery coverage into dedicated route tests

* fix(codex): use chatgpt account id for live model sync

* Add GitHub-backed Codex model discovery fallback

* fix(providers): tighten oauth config tests and provider model display comments

* test: align client version expectations with release default

* fix(codex): keep discovery complexity within baseline

* fix: rebase live Codex model discovery onto release/v3.8.47, preserving kimi-web buildHeaders (#6308)

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-11 05:05:27 -03:00
Diego Rodrigues de Sa e Souza
fa7eb61a05 fix(i18n): backfill 194 missing pt-BR keys (#6695) (#6723)
* fix(i18n): backfill 194 missing pt-BR keys and add key-parity regression test (#6695)

* Merge branch 'release/v3.8.47' into fix/6695-i18n-drift

Resolve i18n key-parity and CHANGELOG-fragment conflicts:
- Convert the #6695 CHANGELOG.md bullet to a changelog.d/ fragment
  (the fragment convention landed on release/v3.8.47 after this PR
  branched, per changelog.d/README.md).
- Backfill 61 additional pt-BR keys that entered en.json on
  release/v3.8.47 after this PR's original 194-key backfill, so the
  PR's own key-parity regression test (tests/unit/i18n-pt-br.test.ts)
  stays green against the moving release baseline.
2026-07-11 05:04:42 -03:00
Diego Rodrigues de Sa e Souza
2c413f2b75 feat: sidebar search/filter input (#4013) (#6810)
* feat(dashboard): add search/filter input to the dashboard sidebar (#4013)

Adds a search box at the top of the expanded sidebar that filters nav
sections/groups/items client-side by label, so users don't have to
hunt through the growing nav tree. Reuses the existing common.search /
common.noResults i18n keys (no new locale edits needed) and the shared
Input icon="search" pattern. Matching sections auto-expand while
searching and the accordion/pin state is restored once the query is
cleared.

Filtering logic is extracted into a pure filterSidebarSectionsByQuery()
helper (src/shared/utils/sidebarSearch.ts) so it is trivially unit
testable independent of React/next-intl/next-navigation.

* fix(test): move Sidebar.search test to a runner-collected path (test-discovery gate)
2026-07-11 05:04:13 -03:00
Diego Rodrigues de Sa e Souza
9159b286d0 feat: per-model web-search interception rule (#3384) (#6814)
* feat(routing): per-model web-search interception rule (#3384)

Adds a per-provider/per-model interceptSearch rule (src/lib/db/interceptionRules.ts,
key_value namespace interception_rules) that overrides the existing native
web-search bypass defaults (Codex/Gemini/Claude->Claude passthrough) in
webSearchFallback.ts. Wired at the existing prepareWebSearchFallbackBody() call
site in chatCore.ts. Resolution precedence: per-model rule > provider-level rule
> existing native-bypass defaults.

This lands Phase 1-2 of the plan (rule store + search interception). Web-fetch
interception and the dashboard UI toggle are tracked as follow-up phases.

* fix(db): register interceptionRules in localDb re-export layer (db-rules gate)

* fix(db): renumber interception_rules migration 119→120 (collision with model_capability_overrides)
2026-07-11 05:03:56 -03:00
Diego Rodrigues de Sa e Souza
427ee244a3 fix(usage): honor xAI provider-reported exact cost (#6711)
OmniRoute's calculateCost() always estimated request cost from token
counts x static pricing, discarding xAI's exact provider-reported cost
when present. xAI's chat-completions usage object reports the precise
billed cost via cost_in_usd_ticks (docs.x.ai/developers/cost-tracking
and the API reference's usage schema: "TICKS_IN_USD_CENT: i64 =
100_000_000" => 1e10 ticks/USD, e.g. 37756000 ticks ~= $0.0038).

calculateCost()/computeCostFromPricing() now short-circuit to this
exact figure when present -- before any pricing DB lookup, so it also
works for models without a local pricing row -- and still fall back to
the token-based estimate when it is absent. The field is threaded
through both the streaming (extractUsage/normalizeUsage) and
non-streaming (extractUsageFromResponse) usage-extraction paths.

Corrected divisor vs upstream: the upstream PR used /1e12 (a 100x
under-report, e.g. reporting $0.00123 as the doc's $0.123 example);
this port uses the doc-verified /1e10 instead, confirmed against both
the cost-tracking guide and the API reference's usage-object schema.

Inspired-by: https://github.com/decolua/9router/pull/2453

Co-authored-by: ryanngit <74137224+ryanngit@users.noreply.github.com>
2026-07-11 04:33:09 -03:00
Diego Rodrigues de Sa e Souza
5e1a325e72 feat(combo): strict budget-cap fallback policy for auto/* combos (#3470) (#6816)
Auto-combo transparency + budget controls: the engine's budgetCap enforcement
always degraded to the globally cheapest candidate when every candidate
exceeded the cap - silently overspending instead of respecting the cap.

- engine.ts: budgetFallback "cheapest" (default, legacy) | "strict"
  (BudgetExceededError when no candidate fits budgetCap)
- requestControls.ts: X-OmniRoute-Budget-Fallback header +
  resolveRequestAutoControls() consolidating mode/budget/fallback parsing
- resolveAutoStrategy.ts / autoConfig.ts: thread combo-level
  config.budgetFallback and catch BudgetExceededError into an HTTP 402
- chat.ts: switch to the consolidated resolveRequestAutoControls() helper
  (net line reduction, stays under the frozen file-size baseline)

Regression guard: tests/unit/auto-combo-budget-fallback-3470.test.ts
2026-07-11 04:32:26 -03:00
Diego Rodrigues de Sa e Souza
d96bd80343 refactor(usage): type saveRequestUsage with UsageEntry interface + any-budget ratchet (#3512) (#6809)
Replace saveRequestUsage(entry: any) with a typed UsageEntry interface
mirroring the usage_history columns 1:1. Fields stay optional/nullable
since different writers (chatCore success/failure, rejected-request
accounting, Codex Responses WS) populate the row incrementally; tokens
stays unknown since callers pass either raw provider-shaped usage or
the normalized {input,output,cacheRead,...} shape.

Also cleaned the file's other any usages (getUsageHistory filter,
getUsageDb next-cursor cast, appendRequestLog tokens param,
getRecentLogs catch) so it now sits at zero any and can be added to
the check:any-budget:t11 zero-any allowlist.

Documents the DB-entity <-> TS-interface convention in
docs/architecture/CODEBASE_DOCUMENTATION.md Sec 11.
2026-07-11 04:32:10 -03:00
Diego Rodrigues de Sa e Souza
6d3d122b84 feat(dashboard): improve Provider Quota page horizontal density (#3520) (#6815)
QuotaCardGrid stacked every provider group vertically in a single
flex flex-col container, and each group's own card grid didn't go
multi-column until the md breakpoint. Provider groups now flow into a
2-column CSS multi-column layout on very wide (2xl) screens instead of
an unconditional vertical stack, and each group's card grid starts at
2 columns immediately, filling horizontal whitespace sooner on
narrower-but-not-mobile viewports.

Regression guard: tests/unit/quota-card-grid-horizontal-layout.test.ts
2026-07-11 04:31:52 -03:00
Diego Rodrigues de Sa e Souza
7fae224315 feat(providers): manual context-window override for custom models (#4125) (#6822)
Add a manual per-model "Context Window Override" so an operator can correct
a provider's misreported context length (e.g. reports 1M when the real
limit is 128K) instead of the model getting silently dropped from combo
routing once the wrong value lands in the catalog.

Reuses the existing Feature-5004 model_context_overrides table
(source="manual") — already the priority-0 source getModelContextLimit()
(the function combo's context-window filter calls) reads ahead of the
models.dev/registry/static catalog — so no new resolver logic was needed,
only the missing write path:

- PUT /api/provider-models now accepts an optional contextWindowOverride
  (number to set, null to clear), persisted via setModelContextOverride/
  removeModelContextOverride.
- GET /api/provider-models surfaces the current override value + source
  back on each custom-model row.
- CustomModelsSection.tsx: edit form gained a Context Window Override
  input + a badge on the model row when an override is set.

Regression guard: tests/unit/provider-models-context-window-override-4125.test.ts
(manual override wins over a misreported catalog value, GET round-trip,
clearing via null, default-unchanged behavior).
2026-07-11 04:31:35 -03:00
Diego Rodrigues de Sa e Souza
778c3aeab9 fix(kiro): probe IdC region during profileArn discovery, cross-region (recovers #6099) (#6840)
* fix(kiro): route Amazon Q runtime by profileArn region for cross-region IdC

Enterprise AWS IAM Identity Center accounts whose IdC instance lives outside the two
Amazon Q Developer profile regions (us-east-1 / eu-central-1) - e.g. eu-north-1
(Stockholm), start URL https://d-XXXX.awsapps.com/start - showed no limits and returned
502 on every request.

Root cause: the backend used the IdC/OIDC token region (providerSpecificData.region, e.g.
eu-north-1) for every CodeWhisperer runtime call, hitting q.eu-north-1.amazonaws.com - a
host that does not exist as a Q Developer runtime endpoint. Per AWS docs ("Supported
Regions for the Q Developer console and Q Developer profile"), the Q Developer *profile*
(which produces the profileArn and hosts generateAssistantResponse / GetUsageLimits /
ListAvailableModels / ListAvailableProfiles) is only hosted in us-east-1 and eu-central-1,
regardless of the IdC region; "data is stored in the Region where you create the Amazon Q
Developer profile."

Fix (new open-sse/services/kiroRegion.ts) decouples the two regions:
- providerSpecificData.region stays the IdC/OIDC region, used ONLY for
  oidc.{region}.amazonaws.com token mint/refresh.
- The runtime region is derived from the profileArn (resolveKiroRuntimeRegion):
  profileArn region -> a valid stored profile region -> us-east-1. A stored IdC region
  that is not a Q profile region (eu-north-1) is ignored for runtime.
- Profile discovery (discoverKiroProfileArnAcrossRegions) probes the Q profile regions
  (EU IdC -> eu-central-1 first) with the cross-region SSO token instead of q.{idcRegion}.

Wired into: executors/kiro.ts (generateAssistantResponse targets the profile region),
services/usage/kiro.ts (getKiroUsage multi-region discovery + profileArn runtime region so
Limits resolves), services/kiroModels.ts (ListAvailableModels), and
src/lib/oauth/providers/kiro.ts (login-time postExchange profile discovery).

Adds tests/unit/kiro-idc-cross-region.test.ts (15 cases). All Kiro suites pass (60 tests).

* fix(kiro): probe the IdC region too during profileArn discovery (any IdC region)

Make profile discovery general for an IdC in ANY of the ~30 IdC-supported AWS regions
(us-west-2, ap-southeast-2, me-central-1, af-south-1, ...), not just eu-north-1.

buildKiroProfileDiscoveryRegions now probes the two documented Q Developer profile regions
FIRST (us-east-1 / eu-central-1, EU-first for EMEA IdC regions to cut latency), then appends
the IdC/stored region itself as a forward-compatible fallback: if AWS ever co-locates the
profile with the IdC or expands the profile-region list, a same-region probe still finds it.
Probing a region with no profile simply returns nothing and we fall through. The profileArn's
own region remains authoritative for every runtime call (resolveKiroRuntimeRegion), so a
newly-issued ARN in any region is honored automatically.

Adds ap-southeast-2 (APAC) cross-region coverage and updates the discovery-order tests.

---------

Co-authored-by: artickc <artur1992123@mail.ru>
2026-07-11 04:25:47 -03:00
Ray Doan
691dae7079 feat(proxy): implement latency-optimized proxy rotation strategy (#6798)
* feat(proxy): implement latency-optimized proxy rotation strategy

Reconstructed onto release/v3.8.47 to drop unrelated main-drift (deps/electron/proxy
files belong to #6620, not this PR) and the direct CHANGELOG.md edit (fragments-first);
the author's env/docs/i18n deltas were re-applied cleanly onto the release tip.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(proxy): add latency-rotation env var to .env.example

PROXY_LATENCY_WINDOW_HOURS was referenced in src/lib/db/proxies.ts and
documented in docs/reference/ENVIRONMENT.md, but missing from
.env.example, tripping the env/docs sync gate.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* chore(changelog): re-sync CHANGELOG.md to release tip

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* refactor(proxy): extract latency-strategy helpers to keep frozen files under cap

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* test(db-rules): expect 35 audited modules (proxyLatency joins INTENTIONALLY_INTERNAL)

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-11 03:47:10 -03:00
lunkerchen
b6ab8ba1ec feat(i18n): add Traditional Chinese (zh-TW) localization for frontend and CLI (#6320)
* feat(i18n): add Traditional Chinese (zh-TW) localization for frontend and CLI

- Add src/i18n/messages/zh-TW.json translating frontend web UI
- Add bin/cli/locales/zh-TW.json translating CLI commands and descriptors
- Register zh-TW in config/i18n.json and docs/guides/I18N.md
- Update scripts/i18n/generate-multilang.mjs matching the new locale setup

* fix: update i18n locale count from 42 to 43 after adding zh-TW

The docs strict checker (check-docs-counts-sync.mjs) validates that
README.md and I18N.md reflect the real locale count. Adding zh-TW
bumped the count from 42 → 43.

* fix(i18n): translate providers free-filter labels in zh-TW (#6694 guard)

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: lunkerchen <lunkerchen@users.noreply.github.com>
2026-07-11 02:15:44 -03:00
Xiangzhe
dfe064861e Clamp reasoning token buffer to model output cap (#6714)
* fix(combo): clamp reasoning buffer to model output cap

* fix(routing): preserve near-cap reasoning max tokens

* fix(routing): getExplicitModelOutputCap falls through to registry cap on non-numeric synced limit_output

getExplicitModelOutputCap short-circuited to null whenever a synced
capability row existed, even if that row's limit_output was not a number
(models.dev commonly omits it). That silently disabled the reasoning-token
buffer clamp for any model with a synced row lacking an output limit.

Now only return the synced value when it IS a number; otherwise fall
through to registryModel.maxOutputTokens / spec.maxOutputTokens, matching
the ??-chain precedence already used by getResolvedModelCapabilities().

Adds a standalone regression test (proves the fallthrough returns the real
registry cap, not null) and hardens the #6274 fixture id so its no-output-cap
case does not prefix-match the real glm-5.2 static spec.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* chore(stryker): register ollama-quota covering tests (release drift from merge burst)

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-11 02:10:56 -03:00
backryun
c92bdd13c6 fix(lmarena): modernize Arena web provider + static Direct-chat catalog (#6280)
* fix(lmarena): modernize Arena web provider + static Direct-chat catalog

Update the lmarena provider for arena.ai (product rebranded from LMArena):

- Route chat via arena.ai create-evaluation with Chrome TLS impersonation
  (tls-client-node) and optional browser-minted recaptchaV3Token.
- Seed Text+Search (48) into the chat registry; seed Image (27) only into
  IMAGE_PROVIDERS. Disable live HTML model discovery; resolve public names to
  Arena UUIDs from the static TypeScript allowlist (no scrape JSON in-repo).
- Soft-exclude 404/502 model ids; slow/stop bulk test-all probes for this provider.
- Do not fold IMAGE_PROVIDERS/video specialty into the chat provider catalog when
  a chat registry already exists (lmarena/openai/xai).
- Display name Arena (Free); keep wire id `lmarena` / alias `lma` for back-compat.
- Theme-aware provider icons: arena-light.svg / arena-dark.svg.
- Preserve split Supabase SSR cookie reconstruction for arena-auth-prod-v1.*.

* fix(providers): align provider-models-route test fixture + regen provider reference

Fold the topaz image-only catalog entry's apiFormat/supportedEndpoints
into the local-catalog test fixture (route now tags media-only
providers per the lmarena PR's staticModels.ts change), regenerate
PROVIDER_REFERENCE.md against the merged release providers.ts, and add
the changelog fragment for #6280.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* test: align web-cookie fallback suite — lmarena now has a registry entry (probe path)

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-11 01:33:24 -03:00
Xiangzhe
65890d4aab fix(logs): prevent stale detail refresh reopening modal (#6323)
* fix(logs): prevent stale detail refresh reopening modal

* chore(stryker): register ollama-quota covering tests (release drift from merge burst)

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-11 01:03:17 -03:00
Septianata Rizky Pratama
45310f202d fix: auto-start WS server in-process and change default port to 20132 (#6072)
* feat: change default LIVE_WS_PORT from 20129 to 20132

Update the default WebSocket port for the live dashboard server from 20129 to 20132 across all configuration files, documentation, code comments, and tests. Also consolidate OMNIROUTE_DISABLE_LIVE_WS and OMNIROUTE_ENABLE_LIVE_WS into a single OMNIROUTE_ENABLE_LIVE_WS flag. Wire the live WebSocket server to start in-process via instrumentation-node.ts.

* feat: clarify NEXT_PUBLIC_LIVE_WS_PUBLIC_URL path usage and derive upgrade path from URL

Update .env.example and ENVIRONMENT.md to document that the pathname portion of NEXT_PUBLIC_LIVE_WS_PUBLIC_URL (e.g. /live-ws) is used as the WebSocket upgrade path by the dev proxy, handshake response, and client connection logic.

Extract deriveLiveWsPath() into shared/utils/wsPath.ts and wire it through:
- src/app/api/v1/ws/route.ts — handshake response path field
- src/hooks/useLiveDashboard.ts — build

* fix: use the standard URL API to safely parse and update the effectiveWsUrl

* build(docker): expose live WebSocket server port and configure CORS origins

Add LIVE_WS_PORT (20132), LIVE_WS_HOST (0.0.0.0), and LIVE_WS_ALLOWED_ORIGINS environment variables to all Docker Compose profiles and expose the WebSocket port mapping. Prevent infinite self-loop in standalone-server-ws.mjs by skipping proxy when the server itself is running on the LiveWS port.

* docs(env): fix comment formatting for HOST and HOSTNAME variables

---------

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-07-11 01:01:27 -03:00