mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-09 17:28:51 +00:00
|
Some checks failed
Publish Fork Image to GHCR / Build and Push Fork Image (push) Waiting to run
CI / Change Classification (push) Waiting to run
CI / Lint (push) Waiting to run
CI / Quality Ratchet (push) Blocked by required conditions
CI / Quality Gates (Extended) (push) Waiting to run
CI / Docs Sync (Strict) (push) Waiting to run
CI / Docs Lint (prose — advisory) (push) Waiting to run
CI / i18n UI Coverage (push) Waiting to run
CI / Build language matrix (push) Waiting to run
CI / i18n Validation (push) Blocked by required conditions
CI / PR Test Policy (push) Waiting to run
CI / Build (push) Blocked by required conditions
CI / Package Artifact (push) Blocked by required conditions
CI / Electron Package Smoke (push) Blocked by required conditions
CI / Unit Tests (1/8) (push) Blocked by required conditions
CI / Unit Tests (2/8) (push) Blocked by required conditions
CI / Unit Tests (3/8) (push) Blocked by required conditions
CI / Unit Tests (4/8) (push) Blocked by required conditions
CI / Unit Tests (5/8) (push) Blocked by required conditions
CI / Unit Tests (6/8) (push) Blocked by required conditions
CI / Unit Tests (7/8) (push) Blocked by required conditions
CI / Unit Tests (8/8) (push) Blocked by required conditions
CI / Vitest (MCP / autoCombo / UI components) (push) Blocked by required conditions
CI / Node 24 Compatibility Tests (1/4) (push) Blocked by required conditions
CI / Node 24 Compatibility Tests (2/4) (push) Blocked by required conditions
CI / Node 24 Compatibility Tests (3/4) (push) Blocked by required conditions
CI / Node 24 Compatibility Tests (4/4) (push) Blocked by required conditions
CI / Node 26 Compatibility Build (push) Blocked by required conditions
CI / Node 26 Compatibility Tests (1/4) (push) Blocked by required conditions
CI / Node 26 Compatibility Tests (2/4) (push) Blocked by required conditions
CI / Node 26 Compatibility Tests (3/4) (push) Blocked by required conditions
CI / Node 26 Compatibility Tests (4/4) (push) Blocked by required conditions
CI / Coverage Shard (1/8) (push) Blocked by required conditions
CI / Coverage Shard (2/8) (push) Blocked by required conditions
CI / Coverage Shard (3/8) (push) Blocked by required conditions
CI / Coverage Shard (4/8) (push) Blocked by required conditions
CI / Coverage Shard (5/8) (push) Blocked by required conditions
CI / Coverage Shard (6/8) (push) Blocked by required conditions
CI / Coverage Shard (7/8) (push) Blocked by required conditions
CI / Coverage Shard (8/8) (push) Blocked by required conditions
CI / Coverage (push) Blocked by required conditions
CI / SonarQube (push) Blocked by required conditions
CI / PR Coverage Comment (push) Blocked by required conditions
CI / E2E Tests (1/9) (push) Blocked by required conditions
CI / E2E Tests (2/9) (push) Blocked by required conditions
CI / E2E Tests (3/9) (push) Blocked by required conditions
CI / E2E Tests (4/9) (push) Blocked by required conditions
CI / E2E Tests (5/9) (push) Blocked by required conditions
CI / E2E Tests (6/9) (push) Blocked by required conditions
CI / E2E Tests (7/9) (push) Blocked by required conditions
CI / E2E Tests (8/9) (push) Blocked by required conditions
CI / E2E Tests (9/9) (push) Blocked by required conditions
CI / Integration Tests (1/2) (push) Blocked by required conditions
CI / Integration Tests (2/2) (push) Blocked by required conditions
CI / Security Tests (push) Blocked by required conditions
CI / CI Dashboard (push) Blocked by required conditions
Publish to Docker Hub / Resolve Docker release metadata (push) Waiting to run
Publish to Docker Hub / Build Docker (linux/amd64) (push) Blocked by required conditions
Publish to Docker Hub / Build Docker (linux/arm64) (push) Blocked by required conditions
Publish to Docker Hub / Publish multi-arch manifests (push) Blocked by required conditions
OpenSSF Scorecard / Scorecard analysis (push) Waiting to run
semgrep / semgrep (push) Waiting to run
opencode-plugin CI / Test (Node 22) (push) Has been cancelled
opencode-plugin CI / Test (Node 24) (push) Has been cancelled
Wiki Sync / Sync wiki with docs (push) Has been cancelled
opencode-plugin CI / Build (push) Has been cancelled
* chore(release): open v3.8.43 development cycle
* docs(relay): clarify backend routing contract (#5621)
Integrated into release/v3.8.43 (drift-shed: cherry-picked the real change onto the release tip; stale-base drift dropped).
* fix(security): avoid rendering error stacks (#5624)
Integrated into release/v3.8.43 (drift-shed: cherry-picked the real change onto the release tip; stale-base drift dropped).
* fix(chatgpt-web): restore dot-form Pro model ids (#5549)
Integrated into release/v3.8.43 (drift-shed: cherry-picked the real change onto the release tip; stale-base drift dropped).
* feat(commandCode): add multimodal image support for CC vision models (#5557)
Integrated into release/v3.8.43 (drift-shed: cherry-picked the real change onto the release tip; stale-base drift dropped).
* fix(providers): validate M365 Copilot web credentials (#5432)
Integrated into release/v3.8.43 (drift-shed: cherry-picked the real change onto the release tip; stale-base drift dropped).
* fix(sse): bound chat hot-path heap — pressure-aware admission + response cap + clone reductions (#5152) (#5425)
Integrated into release/v3.8.43 (drift-shed: cherry-picked the real change onto the release tip; stale-base drift dropped).
* fix: model lockout not recording for 429 rate_limit_exceeded from Antigravity
## Problem
When Antigravity returns HTTP 429 with `rate_limit_exceeded` error code,
the model lockout system never records the failure, so the model is not
cooled down despite being rate-limited.
### Root Cause
Antigravity's 429 error text is: `"Resource has been exhausted (e.g. check
quota)."`
The QUOTA_PATTERNS in `classify429.ts` contained overly broad regexes:
- `/resource.*exhaust/i` — matches "Resource has been exhausted"
- `/check.*quota/i` — matches "check quota"
This caused `classifyErrorText()` to return `QUOTA_EXHAUSTED` (wrong),
which set `providerExhausted = true` in the combo target exhaustion logic.
With `providerExhausted`, the retry path was skipped entirely, and while
the "done retrying" path should still record lockout, the misclassification
cascaded into incorrect provider-level exhaustion state.
Additionally, `targetExhaustion.ts` used the raw error text string instead
of the structured error code (`rate_limit_exceeded`) that was already
parsed from the response body.
## Fix
1. **classify429.ts** — Removed overly broad `/resource.*exhaust/i` and
`/check.*quota/i` from QUOTA_PATTERNS. Antigravity's rate-limit wording
is not a true quota exhaustion signal.
2. **targetExhaustion.ts** — Added optional `structuredError` to
`ApplyComboTargetExhaustionOptions`. When available, the structured
error code (e.g. `rate_limit_exceeded`) takes precedence over raw error
text for exhaustion classification.
3. **combo.ts** — Passes `structuredError` to both `applyComboTargetExhaustion`
call sites (dispatch path + retry-or-rotate path).
## Effect
`structuredError.code = "rate_limit_exceeded"` → classified as rate-limit
(not quota) → `providerExhausted = false` → retry proceeds →
`recordModelLockoutFailure` called → model enters lockout with proper
cooldown (120s base, exponential backoff).
## Tests
Added 2 new tests for `structuredError.code` precedence in exhaustion
classification. All 28 related tests pass.
* fix(checks): normalize route paths on windows (#5613)
Integrated into release/v3.8.43. Windows path-normalization fix for the route-guard membership gate + regression test (Rule #18). Co-authored test added by maintainer.
* fix: truncate tool list when provider limit exceeds MAX_TOOLS_LIMIT (grok-cli 200)
- Add proactive PROVIDER_TOOL_LIMITS map with grok-cli: 200
- Fix regex to capture 'maximum is 200' (not '427 tools provided')
- Remove broken truncation gate that skipped limits >= MAX_TOOLS_LIMIT (128)
- Add tests for Grok regex, proactive limits, and limits above threshold
Refs #5563
* test(chatcore): cover grok-cli tool-list truncation via prepareUpstreamBody (#5563)
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* fix(security): v3.8.15 hardening follow-ups (Seg2/Seg3/Seg4/Bug3) (#5512)
Security v3.8.15 hardening follow-ups: Seg2 (CHANGEME boot warn), Seg3 (auth_token cookie maxAge 30d), Seg4 (VS Code path-token once-per-process warning), Bug3 (real global install path resolution), Bug1 (segment-match node_modules in auto-update detection). All 5 carry TDD regression guards.
* Fix HuggingChat web session routing (#5592) (#5592)
Integrated into release/v3.8.43. HuggingChat web session-routing fix (root parent-message fetch + cookie propagation + encrypted-credential guard) + 24-model catalog refresh. Maintainer adjustments (co-authored): reverted the freeModelCatalog.data.ts whole-file reformat down to the surgical 24-record huggingchat change (preserving the auto-generated compact format), and added a 502 regression test for the null parent-message-id path (Rule #18).
* fix: preserve system role for GLM 5.1/5.2 (#5610) (#5663)
* fix: restore Codex Responses WS TLS profile + apply proxy (#5591, #5611) (#5668)
* fix: allow saving providers without a live validator (#5565, #5567) (#5669)
* fix: static model catalog for jules/linkup/ollama/searchapi search providers (#5569, #5571, #5573, #5575) (#5672)
* fix: live AI/ML API catalog + deprecate dead CablyAI (#5570, #5568) (#5673)
* fix: correct 404 provider setup links for ollama/searchapi/you.com (#5572, #5574, #5576) (#5674)
* fix: page call_logs cleanup queries to avoid startup OOM on large DBs (#5618) (#5675)
* fix: use PowerShell Expand-Archive on Windows for embedded-service install (#5590) (#5678)
* fix: treat array content blocks as valid output in detectMalformedNonStream (#5559) (#5680)
* fix: render memory engine status detail strings in English (#5596) (#5685)
* fix: free proxy pool silent sync failure — iplocate txt + per-source isolation + surface errors (#5595) (#5686)
* chore(quality): close QG v2 tail — drop orphan semcheck.yaml + Fase 9 maturity re-eval (#5681)
- Remove semcheck.yaml: orphan config (zero workflow/script wiring) with stale
rule counts; deterministic doc-accuracy coverage already exists
(check:fabricated-docs --strict + docs-counts-sync + docs-symbols). Drop the
REPOSITORY_MAP row referencing it.
- Add docs/ops/MATURITY_REEVAL.md (Fase 9): re-measures maturity post-Ondas 0-3.
The two biggest structural weaknesses from QUALITY_GATE_PLAYBOOK (2026-06-16) are
now closed: fast-gates hole (quality.yml runs typecheck:core + impacted TIA unit
tests + vitest + shards) and mutation-score-as-ratchet (check-mutation-ratchet.mjs
+ seeded baseline + nightly blocking job). Residual gap is owner/infra-gated
(branch-protection main, SLSA L3, CodeQL advanced).
- Record agent-lsp as deferred/opt-in (doc-only scaffold, no wiring).
* fix(ci): stabilize nightly-mutation — guard tap.testFiles drift + anti-flake eps (#5682)
Root cause (NOT a timeout): the nightly-mutation run fails on cold-cache nights
because the blocking mutation-ratchet job measures modules below baseline, while
warm-cache nights pass — the verdict tracked GitHub Actions cache state, not code
quality. Proven via a local Stryker probe on headers.ts: covering unit tests
(no-memory-header, strip-reasoning) had drifted OUT of stryker.conf.json
tap.testFiles, so their mutants went covered-but-unkilled = Survived on a cold
full run (COVERED score 61.73 vs 94.29 baseline); adding them restores the kills.
- Add scripts/check/check-mutation-test-coverage.mjs: guards that every UNIT test
importing a Stryker-mutated module is listed in tap.testFiles. Advisory by
default, --strict in CI (wired in quality.yml fast-gates). Prevents recurrence.
- Add the 38 drifted covering unit tests to stryker.conf.json tap.testFiles
(138 -> 176). Monotonically safe: more covering tests only raise/hold the score.
- Add MUTATION_RATCHET_EPS (1.0pt) anti-flake tolerance to check-mutation-ratchet
so sub-point tap-runner jitter no longer false-fails the gate. Lowers no baseline.
- Tests: check-mutation-test-coverage (3) + eps cases in check-mutation-ratchet.
Residual: a clean post-merge nightly confirms scores return to/above baseline;
any marginal residual gets a baseline re-seed (operator).
* refactor(dashboard): split sidebarVisibility god-file into types + sections leaves (#5683)
Behavior-preserving decomposition: src/shared/constants/sidebarVisibility.ts
1197 -> 291 LOC by extracting two leaves under sidebarVisibility/:
- types.ts (160): HIDEABLE_SIDEBAR_ITEM_IDS + all sidebar types (self-contained).
- sections.ts (762): section building-block consts + SIDEBAR_SECTIONS (imports
types only — cycle-safe). COMPRESSION_CONTEXT_GROUP + SIDEBAR_SECTIONS stay
exported; host re-exports both + 'export *' of types, so every consumer import
path is unchanged.
Byte-identical data verified via JSON.stringify of HIDEABLE_SIDEBAR_ITEM_IDS /
SIDEBAR_ICON_ACCENTS / COMPRESSION_CONTEXT_GROUP / SIDEBAR_SECTIONS / SIDEBAR_PRESETS
+ getSectionItems output (identical before/after). typecheck:core, check:cycles
(no cycles), check:file-size (3 files <800), and the 3 sidebar suites (20/20) pass.
No logic changed.
Note: file-size frozen baseline for sidebarVisibility.ts (1198) can ratchet to 291
to lock the shrink (left for the release ratchet / operator).
* fix: surface fusion-specific config on the Global Routing tab (#5598) (#5688)
* fix(executor): route OpenAI-compatible MCP Responses requests to /responses (#5483)
Closes #5483. OpenAI-compatible providers receiving a Responses-shaped request carrying MCP / tool_search tools now route to the upstream /responses endpoint instead of downgrading to /chat/completions, preserving Codex deferred tool discovery. Detection helpers extracted to open-sse/executors/forceResponsesUpstream.ts. Thanks to @KooshaPari.
* fix(ci): make release-green pre-flight gates visible + bounded so unit reds are not missed (#5644)
Integrated into release/v3.8.43.
* fix(body-size): raise LLM API payload limit for responses routes (#5652)
Integrated into release/v3.8.43. Thanks @JxnLexn!
* fix(test): use lightweight health probe for batch e2e (#5651)
Integrated into release/v3.8.43. Thanks @KooshaPari!
* feat(compression): T05/C5 — preserveSystemPrompt mode enum + legacy back-compat (#5653)
Integrated into release/v3.8.43. Includes the legacy-boolean back-compat derivation so existing preserveSystemPrompt=false installs keep whenNoCache behavior.
* routing: optimize latency strategy with perf metrics (#5629)
Integrated into release/v3.8.43. Thanks @KooshaPari!
* feat(db): models/5004 — self-correcting model context-window overrides (#5667)
Integrated into release/v3.8.43.
* feat(providers): complete SenseNova free Token Plan — chat + Text-to-Image (port from 9router#2233) (#5679)
Integrated into release/v3.8.43.
* feat(api): routing/4985 — configurable response-body validation + failover (#5684)
Integrated into release/v3.8.43.
* fix(chatcore): default Claude tool type to "custom" when missing (#5662)
Integrated into release/v3.8.43. Port from 9router#2196.
Co-authored-by: warelik <warelik@users.noreply.github.com>
* fix(translator): merge consecutive same-role contents for Gemini (port from 9router#2191) (#5661)
Integrated into release/v3.8.43. Port from 9router#2191.
* chore(bun): add locked bun runtime dependency (#5615)
Integrated into release/v3.8.43. Bun 1.3.10 pinned via npm lockfile (adopt-partial decision). Thanks @KooshaPari!
* chore(bun): run validated ts scripts with bun (#5612)
Integrated into release/v3.8.43. Thanks @KooshaPari!
* chore(bun): run CI script checks with bun (#5617)
Integrated into release/v3.8.43. Validated bun==node output for all 3 gates (provider-consistency, compression-budget, known-symbols). Thanks @KooshaPari!
* fix(build): make pack validator bun safe (#5643)
Integrated into release/v3.8.43. Forward-compat guard; node/npm path unchanged. Thanks @KooshaPari!
* docs: document Bun as the allow-listed build/dev script runner (Node stays the published runtime) (#5703)
Integrated into release/v3.8.43.
* feat(analytics): show $0 cost for flat-rate subscription/cookie providers (#5552) (#5704)
* refactor(api): extract unified-catalog helpers into cohesive leaf modules (#5699)
BLOCO E2 of the god-files campaign. The module-level pure/standalone helpers in
src/app/api/v1/models/catalog.ts (1611 LOC) were lifted out verbatim into five
cohesive leaf modules so the catalog host shrinks toward the 800-LOC file-size cap
without any behavior change (host now 1345 LOC; the heavy getUnifiedModelsResponse
orchestrator is untouched — its in-function closures stay put):
- catalogHelpers.ts — pure numeric/array/shape helpers + shared catalog types
- catalogOpenrouter.ts — OpenRouter id/modality/free-model/display-name helpers
- catalogVision.ts — vision-capability field derivation (+ isVisionModelId re-export)
- catalogProviderMaps.ts — alias<->providerId resolution maps (buildAliasMaps)
- catalogRequest.ts — /v1/models API-key auth gating + Codex CLI client detection
The host re-exports getCustomVisionCapabilityFields and isVisionModelId so the public
API consumed by other tests (llm-selector-custom-vision-models, vision-detection-
consistency) is unchanged; all 9 catalog/vision suites stay green.
Adds tests/unit/catalog-helpers-extraction.test.ts: characterization tests for every
extracted helper + a guard asserting the host preserves its public exports.
Validated: typecheck:core, 50 catalog characterization tests, 12 new leaf tests,
integration-wiring, check:cycles, check:file-size (no new violations), ESLint, Prettier.
* feat(mcp): T07 — expose RTK learn/discover as MCP tools (#5691)
Adds two read-only MCP tools wrapping the existing RTK discovery primitives: omniroute_rtk_discover (discoverRepeatedNoise/suggestFilter over recently captured raw tool output → candidate noise patterns + suggested filter) and omniroute_rtk_learn (listRtkCommandSamples + commandToId). Scope read:compression, MCP audit-logged, no new engine logic. Regression guard: tests/unit/compression/rtk-mcp-tools.test.ts. gaps v3.8.42 — T07.
* feat(compression): T05/C3 — opt-in LLM-tier compression engine (#5702)
Adds an opt-in, default-off LLM-tier compression engine ('llm') that condenses non-system message prose via a pluggable chat-completion backend, mirroring the llmlingua contract. Safe by construction: no-op default backend (pass-through out of the box), not in the default stacked pipeline, enabled defaults false, fenced code blocks + system messages never sent to the model, fail-open everywhere, minTokens floor. Real production backend is a VPS-validated follow-up (Hard Rule #18). Regression guard: tests/unit/compression/llm-compressor-engine.test.ts (8). gaps v3.8.42 — T05/C3.
* refactor(db): extract compat/aliases/mitm helpers from db/models.ts into leaf modules (#5705)
BLOCO E3 of the god-files campaign. db/models.ts (1250 LOC) mixed six concerns; the
three cleanly-separable ones plus the shared key_value helpers were lifted out verbatim
into a new src/lib/db/models/ subdirectory, leaving the tightly-coupled custom/synced/
flags trio in the host (host now 936 LOC). The host re-exports every moved public symbol
so the module's public API (consumed by ~29 test files + localDb) is unchanged.
- models/shared.ts — asRecord / toNonEmptyString / getKeyValue + JsonRecord (19 LOC)
- models/compat.ts — model-compat overrides + sanitizeUpstreamHeadersMap (249 LOC)
- models/aliases.ts — model-alias CRUD + cascade delete (61 LOC)
- models/mitmAlias.ts — MITM alias get/set (32 LOC)
The custom/synced/flags trio stays in the host because it is genuinely coupled
(flags->getCustomModelRow, flags->readCompatList, custom->removeModelCompatOverride,
synced->getModelIsDeleted, setModelIsHidden->updateCustomModel) — splitting it cleanly
is a follow-up. Dependency DAG is acyclic (verified by check:cycles).
Adds tests/unit/db-models-split.test.ts: characterization of the pure extracted helpers
+ a guard asserting the host preserves its full public export surface.
Validated: typecheck:core, check:cycles (no cycles), 77 existing db/models consumer
tests (db-models-crud/extended/aliases-cascade + 7 more) green, 7 new tests, ESLint,
Prettier, check:file-size (host 936 < frozen 1259; no new violations).
* refactor(db): extract pricing/lkgp/cache-metrics from db/settings.ts into leaf modules (#5709)
BLOCO E3 of the god-files campaign. db/settings.ts (1154 LOC) mixed five concerns; the
three cleanly-separable ones plus the shared toRecord/JsonRecord helper were lifted out
verbatim into a new src/lib/db/settings/ subdirectory, leaving the Settings-core + Proxy
config concerns in the host (host now 646 LOC). The host re-exports every moved public
symbol so the module's public API (consumed by ~93 test files + localDb) is unchanged.
- settings/shared.ts — toRecord + JsonRecord (9 LOC)
- settings/pricing.ts — pricing layers/sources/per-model + update/reset (254 LOC)
- settings/lkgp.ts — Last-Known-Good-Provider get/set/clear (49 LOC)
- settings/cacheMetrics.ts — cache metrics + trend (235 LOC)
Settings-core + the Proxy-config concern stay in the host: proxy is the most tangled
(245-line resolveProxyForConnection, resolution cache, imports from ./proxies) and
getSettings is the most central function — leaving them is the correct coupled-core stop.
Pricing/LKGP/Cache have NO dependency on Settings/Proxy helpers (verified); the
dependency DAG is acyclic (check:cycles).
Adds tests/unit/db-settings-split.test.ts: characterization of the shared toRecord helper
+ a guard asserting the host preserves its full public export surface.
Validated: typecheck:core, check:cycles (no cycles), 149 existing+new db/settings consumer
tests green (db-settings-crud/extended, 8 pricing suites, cache-metrics, 2 proxy-resolution
suites + 29 new), ESLint, Prettier, check:file-size (host 646 < frozen 1155).
* fix(translator): re-apply lost defensive hardening for Gemini merge + Claude tool defaults (#5706)
Re-applies two dropped gemini-code-assist hardening fixes (defaultClaudeToolType non-object passthrough; mergeConsecutiveSameRoleContents shallow-copy) with regression tests. Follow-up to #5661/#5662. Integrated into release/v3.8.43.
* feat(codex): generate fallback profiles for compatible models (#5701)
setup-codex now generates Codex profiles for compatible text models from the live /v1/models catalog when the model id doesn't match a hand-tuned pattern, skipping media/embedding models. Integrated into release/v3.8.43.
* docs(changelog): credit @Chewji9875 for #5563 + #5579
Add CHANGELOG credit bullets for grok-cli tool-limit (#5563) and Antigravity 429 lockout (#5579). Documentation-only.
* test(dashboard): repoint sidebar quota-share placement scan to sections.ts (#5711)
The D1 god-file split (#5683) moved the nav-item id definitions out of
src/shared/constants/sidebarVisibility.ts into the extracted leaf
src/shared/constants/sidebarVisibility/sections.ts. This source-scan test
still read the old monolith path, so it found 0 occurrences of
id: "costs-quota-share" and failed (base-red on release/v3.8.43).
Repoint SIDEBAR_PATH to sections.ts where the ids now live. All four
placement assertions (quota-share after quota, same array, far from
costs-budget, exactly one occurrence) hold against the new source.
* refactor(db): extract columns/nodes/rate-limit leaves from db/providers.ts (#5714)
db/providers.ts was a 1106-line god-file mixing four concerns. Extract the
three acyclic, cohesive slices into sibling leaf modules under
src/lib/db/providers/, leaving the tightly-coupled connection-CRUD core in
the host:
- providers/columns.ts (116) 10 pure column-normalizer helpers (DB-free)
- providers/nodes.ts (163) 6 provider-node CRUD functions
- providers/rateLimit.ts (177) 6 rate-limit/quota runtime helpers + formatResetCountdown
Host providers.ts: 1106 -> 719 lines. The connection-CRUD core does not call
any node or rate-limit function (verified), so the host re-exports the 12
moved public symbols via `export { ... } from './providers/<leaf>'` — the
module's public API stays IDENTICAL (23 symbols). Bodies moved verbatim
(byte-identical); the only edit to a moved line is the added `export` on the
10 previously-private normalizers.
Behavior-preserving: 122 existing provider/quota/rate-limit consumer tests
stay green; new tests/unit/db-providers-split.test.ts guards the re-export
barrel + characterizes the pure column helpers (38 assertions).
Refs #3501 (god-file structural shrink).
* refactor(db): extract types + pure mappers from db/proxies.ts (#5717)
db/proxies.ts was a 1059-line god-file. Extract the two acyclic, DB-free
slices into sibling leaf modules under src/lib/db/proxies/, leaving the
tightly-coupled CRUD + assignment + resolution core in the host:
- proxies/types.ts (65) 10 proxy type/interface declarations
- proxies/mappers.ts (180) pure row mappers / scope normalizers / payload
coercers (toRecord, mapProxyRow, mapAssignmentRow,
isRelayProxyType, extractRelayAuth,
toRegistryProxyResolution, normalizeScope,
normalizeAssignmentScopeId, toLegacyProxyLevel,
coerceProxyPayload, redactProxySecrets)
Host proxies.ts: 1059 -> 847 lines. The resolution functions call
createProxy/assignProxyToScope, so the CRUD+resolution core CANNOT be
extracted without an import cycle and stays in the host. The host re-exports
the 2 moved public functions (extractRelayAuth, redactProxySecrets) via
`export { ... } from './proxies/mappers'` — the public API stays IDENTICAL
(20 functions; no types were ever publicly exported). Bodies moved verbatim;
the only host edits are the new leaf imports, the re-export, dropping the now
unused `import { decrypt }`, and two prettier line-wrap reflows of retained
ternary/union lines (token-identical).
Behavior-preserving: 69 existing proxy/registry/relay/family consumer tests
stay green; new tests/unit/db-proxies-split.test.ts guards the re-export
barrel + characterizes the pure mappers (35 assertions).
Refs #3501.
* refactor(db): extract static migration data tables from migrationRunner.ts (#5721)
migrationRunner.ts (1124 lines, frozen-baselined) is the startup migration
orchestrator. As a conservative, zero-behaviour-risk first slice, extract the
six static migration-compatibility DATA tables (verbatim) into a pure-data
leaf, leaving the entire orchestrator + all SQL-running helpers in the host:
- migrationRunner/constants.ts (118) RENAMED_MIGRATION_COMPATIBILITY,
LEGACY_VERSION_SLOT_MIGRATIONS, SUPERSEDED_DUPLICATE_MIGRATIONS,
PHYSICAL_SCHEMA_SENTINELS, INITIAL_SCHEMA_SENTINELS,
OPTIONAL_FTS5_MIGRATION_VERSIONS
Host migrationRunner.ts: 1124 -> 1023. The runtime fts5SupportCache (a
WeakMap, mutable state) stays in the host. No public API change (these consts
were module-internal). Data moved byte-identical (sed-extracted, verbatim
verified); the only host edits are the leaf import + one prettier collapse of
a pre-existing 2-line union type annotation to 1 line (token-identical,
typecheck-confirmed).
Characterize-first (operator-chosen): the existing db-migration-runner.test.ts
(26 tests) + no-migration-collisions/weak-rng-fixes/check-db-rules (11) prove
the reconciliation/dedup/already-applied BEHAVIOUR is unchanged; the new
tests/unit/db-migrationrunner-constants-split.test.ts (7 tests) PINS THE DATA
(counts + shape + spot-checks of every table) so a dropped/transposed row is
caught immediately.
Refs #3501.
* refactor(db): extract pure SQL-source builders from usageAnalytics.ts (#5722)
usageAnalytics.ts (924 lines, frozen-baselined) mixes two pure SQL-source
builders with ~20 getXxxRows() query functions. Extract the contiguous,
DB-free builder block verbatim into a leaf, leaving every query function in
the host:
- usageAnalytics/sources.ts (208) AnalyticsParams, BuildUnifiedSourceOptions,
UnifiedSourceResult + buildUnifiedSource + buildPresetUnifiedSource (pure
string builders; no DB, no imports)
Host usageAnalytics.ts: 924 -> 723. The query functions do not call the
builders (callers build the unified source then pass the string in), so the
host re-exports the 5 moved public symbols (2 fns + 3 types) and imports
AnalyticsParams as a type for its query signatures — the public API stays
IDENTICAL (39 symbols). Builder bodies moved byte-identical; the two orphaned
section-header banners that described the moved block were removed with it;
the retained query-function suffix is byte-identical to the original.
Behavior-preserving: 37 existing analytics consumer tests stay green
(usage-analytics 12, usage-endpoint-dimension 3, db-usage-analytics-3500 22);
new tests/unit/db-usageanalytics-split.test.ts (25 assertions) characterizes
buildUnifiedSource's needsAggregated branching (raw-only vs raw+daily_usage_summary)
+ guards the 39-symbol re-export barrel.
Refs #3501.
* docs(readme): refresh metrics, list 17 strategies, add Quota-Share + real provider logos
- Unify provider count to 236; MCP tools 87->94; cloud agents 3->4 (+Cursor); compression 9->10 engines (+relevance)
- Tests -> 21,000+ across 2,586 files; footer -> v3.8.43
- Raise lower bounds to real values: 90+ free, 80+ commands, 24+ CLIs
- Language flag grid 33->43 (15/14/14, all locales)
- List all 17 routing strategies; new Quota-Share section before Resilience
- Real provider logos (lobe-icons + local agentrouter) in providers grid and Free Forever
- Top Contributors: refreshed stats + add herjarsa; 280+ title; half-size avatars; contrib.rocks 100->200
- Acknowledgments: refreshed star counts; fix headroom repo rename
* docs(readme): update provider counts and add new badges
* feat(memory): T10/TV6 — opt-in typed memory decay (#5723)
Opt-in typed memory decay so the conversational memory store self-prunes stale episodic noise. access_count + last_accessed_at telemetry (migration 111) is always-on/non-destructive; the sweep is opt-in (MEMORY_TYPED_DECAY_ENABLED, default false). Only episodic decays by default (30d); factual/procedural/semantic immune; access_count>=3 earns immunity; deletions reuse deleteMemory (SQLite+vec+Qdrant in sync), fail-open. Regression guard: tests/unit/memory/typed-decay.test.ts (15). gaps v3.8.42 — T10/TV6.
* feat(dashboard): T06/T03 — drag-reorder compression pipeline editor + studio e2e (#5727)
T06: named-combos editor gains a @dnd-kit/sortable drag-to-reorder stacked pipeline backed by a pure model (compressionPipelineModel.ts: add/remove/move/update, engine->intensity invariant, never-empty). CompressionPipelineEditor.tsx replaces the inline fixed list in CompressionCombosPageClient; order persists via the existing combos endpoint (no API change). T03: adds tests/e2e/compression-studio.spec.ts (Tela A render + Play/Compare tab switch), the dedicated compression-studio e2e combo-live-studio.spec.ts did not cover. TDD: compression-pipeline-model.test.ts (11) + compression-pipeline-editor.test.tsx (4). gaps v3.8.42 — T06 + T03.
* fix(thinking): wire Thinking-Budget boot hydration into live instrumentation path (#5312) (#5729)
hydrateThinkingBudgetConfig was only called from the unused src/server-init.ts,
which never runs in production, so the dashboard Thinking-Budget mode silently
reverted to passthrough on every restart. Wire it into the real boot path
(src/instrumentation-node.ts), next to the Global System Prompt restore.
Surfaced by live Anthropic-OAuth validation on the VPS (fix A of #5312 was
non-functional even though its direct unit test passed). New guard
tests/unit/thinking-budget-boot-wiring-5312.test.ts asserts the production boot
module calls the hydration, closing the test gap that let this ship.
* refactor(usage): extract pure formatting helpers from callLogs.ts (#5725)
callLogs.ts (996 lines, frozen-baselined) mixes pure log-formatting /
sanitization helpers with DB CRUD, disk-artifact, and rotation logic. Extract
the ten pure, DB-free helpers verbatim into a leaf, leaving all stateful code
in the host:
- callLogs/format.ts (129) asRecord, toNumber, toStringOrNull, truncateText,
parseInlineError, normalizeDetailState, sanitizeErrorForLog,
toStoredErrorSummary, protectPipelinePayloads, buildRequestSummary
Host callLogs.ts: 996 -> 885. The stateful generateLogId (mutates logIdCounter)
stays in the host. These helpers were all module-internal, so the public API is
unchanged (10 exported functions). Bodies moved byte-identical; the host's now
unused 'sanitizePII' import (only referenced inside the moved bodies) moved to
the leaf; prettier wrapped buildRequestSummary's signature across lines once the
'export' prefix pushed it past 100 cols (token-identical).
Behavior-preserving: 46 existing call-log consumer tests stay green
(call-log-cap 14, pagination 4, file-rotation 5, log-retention 5, startup 1,
oom 2, trim-sql 2, db-settings-maintenance 13); new
tests/unit/calllogs-format-split.test.ts (26 assertions) characterizes the pure
helpers + guards the 10-function public API.
Refs #3501.
* refactor(usage): extract pure stat/coercer helpers from usageHistory.ts (#5728)
usageHistory.ts (987 lines, frozen-baselined) mixes pure DB-free helpers with
an in-memory pending-request state machine and DB CRUD. Extract the contiguous
pure block verbatim into a leaf, leaving all stateful code in the host:
- usageHistory/helpers.ts (85) asRecord, toStringOrNull, normalizeServiceTier,
toNumber, percentile, stdDev, truncatePendingPreview (+ its MAX_PREVIEW_*
bounds, co-located)
Host usageHistory.ts: 987 -> 916. The pending-request state machine (module
Maps + track/update/finalize/sweep) and DB CRUD stay in the host. These helpers
were all module-internal, so the public API is unchanged (21 direct exports +
the pre-existing getCompletedDetails re-export = 22). Bodies moved byte-identical
(leaf 0 non-verbatim lines); the host's local 'type JsonRecord' moved with the
bodies that used it (host no longer references it — typecheck-confirmed).
Behavior-preserving: 38 existing usage-history consumer tests stay green
(usage-history-db 5, api-key-usage-limits 6, log-retention 5,
usage-endpoint-dimension 3, provider-request-failure-pipeline 6,
database-settings-maintenance 13); new
tests/unit/usagehistory-helpers-split.test.ts (30 assertions) pins the
percentile/stdDev formulas + normalizeServiceTier + guards the public API.
Refs #3501.
* refactor(usage): extract pure quota-normalize helpers from providerLimits.ts (#5730)
providerLimits.ts (954 lines, frozen-baselined) is the heavily DB/network-coupled
provider quota sync module. Extract a small, fully SELF-CONTAINED leaf of pure
quota-key/quota-value normalization helpers (+ the isRecord type guard they
share), leaving all sync/DB/network code in the host:
- providerLimits/quotaNormalize.ts (72) isRecord, isUsageQuotaKeyAllowed,
normalizeUsageQuotaKey, normalizeUsageQuotasForProvider,
sanitizeUsageQuotasForProvider
Host providerLimits.ts: 954 -> 890. The leaf imports only the external
antigravity/agy model-alias helpers the moved bodies reference (moved from the
host's import block) — it does NOT import the host, so check:cycles stays clean
(no cycle). isRecord (used ~9x in the host) is co-extracted and imported back.
These five were all module-internal, so the public API is unchanged (13
exported functions). Bodies moved byte-identical.
Behavior-preserving: 18 existing provider-limits consumer tests stay green
(sanitize-scope 3, db-provider-limits 3, proxy-fail-closed 3,
rotating-expired-guard 7, codex-quota-sync 2); new
tests/unit/providerlimits-quotanormalize-split.test.ts (19 assertions) pins
isRecord + isUsageQuotaKeyAllowed + guards the 13-function public API.
Refs #3501.
* refactor(memory): extract pure scoring/conversion helpers from retrieval.ts (#5733)
retrieval.ts (1192 lines — ABOVE its 1171 frozen baseline) is the memory
retrieval engine (DB + vector + rerank network). Extract the pure, DB-free
scoring/conversion helpers (+ the MemoryRow row shape they share) verbatim into
a self-contained leaf, leaving all DB/vector/network code in the host:
- retrieval/scoring.ts (104) interface MemoryRow + estimateTokens,
parseMetadata, rowToMemory, getRelevanceScore
Host retrieval.ts: 1192 -> 1072 — back UNDER the 1171 frozen baseline (the split
also repairs the pre-existing file-size drift). The leaf imports only ../types,
never the host, so check:cycles stays clean (no cycle). MemoryRow moved to the
leaf and imported back as a type by the host's DB row functions. The public
estimateTokens is re-exported from the leaf; the host also imports it for its
internal token-budget loops. The other three helpers were module-internal, so
the public API is unchanged (7 exports). Bodies moved byte-identical.
Behavior-preserving: 38 existing memory-retrieval consumer tests stay green
(rerank 5, hybrid 6, semantic 6, engine-status 9, stats-api 12); new
tests/unit/retrieval-scoring-split.test.ts (11 assertions) pins
estimateTokens (ceil(len/4)) + parseMetadata + rowToMemory mapping +
getRelevanceScore (+20 phrase / +3 token) and guards the public API.
Refs #3501.
* refactor(sse): extract reasoning-tag detection/extraction from responseSanitizer.ts (#5734)
responseSanitizer.ts (1133 lines, frozen-baselined) mixes reasoning-tag
detection/extraction with response/usage/streaming sanitization. Extract the
cohesive, ZERO-IMPORT reasoning block verbatim into a self-contained leaf:
- responseSanitizer/reasoning.ts (143) the reasoning regex consts +
collapseExcessiveNewlines, cleanReasoningFragment,
splitClosingOnlyReasoningPrefix, movePrefixBeforeContentTagToThinking,
extractThinkingFromContent, normalizeReasoningRouteId,
isAntigravityReasoningRoute, isTextualReasoningTagNativeRoute,
shouldParseTextualReasoningTags
Host responseSanitizer.ts: 1133 -> 1003. The block's helpers only call each
other, so the leaf has ZERO imports — it cannot import the host (check:cycles
clean). The host imports back collapseExcessiveNewlines (6 call sites) +
extractThinkingFromContent, and re-exports the two public symbols
(extractThinkingFromContent, shouldParseTextualReasoningTags) — the public API
stays IDENTICAL (7 exports). Bodies moved byte-identical; two long declarations
(REASONING_TAG_FRAGMENT_REGEX, movePrefixBeforeContentTagToThinking signature)
were line-wrapped by prettier once the 'export' prefix pushed them past 100
cols (token-identical).
Behavior-preserving: 47 existing consumer tests stay green (response-sanitizer
36, strip-reasoning-header 8, textual-toolcall-false-positive 3); new
tests/unit/responsesanitizer-reasoning-split.test.ts (11 assertions)
characterizes extractThinkingFromContent + shouldParseTextualReasoningTags and
guards the public API.
Refs #3501.
* refactor(sse): extract rate-limit header parsing from rateLimitManager.ts (#5736)
rateLimitManager.ts (1034 lines, frozen-baselined) is the stateful rate-limiter
(Bottleneck limiters, watchdog timers, learned-limits Map). Extract the pure,
ZERO-IMPORT header-parsing block verbatim into a self-contained leaf, leaving
all stateful machinery in the host:
- rateLimitManager/headers.ts (94) STANDARD_HEADERS, ANTHROPIC_HEADERS,
parseResetTime, toPlainHeaders
Host rateLimitManager.ts: 1034 -> 945. The four items are pure (no limiter
state, no external deps), so the leaf has ZERO imports — it cannot import the
host (check:cycles clean). The host imports all four back (used by
updateFromHeaders). They were module-internal, so the public API is unchanged
(17 exports). Bodies moved byte-identical.
Behavior-preserving: 21 existing rate-limit consumer tests stay green
(rate-limit-manager 7, limiter-lifecycle 4, queue-timeout-msg 2,
idle-eviction 6, body-lock 2); new
tests/unit/ratelimitmanager-headers-split.test.ts (7 assertions) pins
parseResetTime (durations / bare-number / nullish) + toPlainHeaders + guards
the 17-function public API (with a watchdog-timer teardown hook so the runner
exits cleanly).
Refs #3501.
* fix(config): back boot-hydrated proxy config singletons with globalThis (#5312) (#5742)
Next.js compiles instrumentation.ts as a separate webpack module graph from the
app-route/open-sse executors, so a module-local `let _config` is duplicated:
the boot-time hydration (applyRuntimeSettings / restore hooks) lands on the
instrumentation graph's copy, but the request path (base.ts) reads a different,
un-hydrated copy. Live VPS validation proved the Thinking-Budget hydrate ran to
completion at boot yet base.ts still read the passthrough default — why #5312
fix A stayed broken after the boot-wiring fix.
Back the singletons with globalThis (the pattern systemPrompt.ts already uses for
#2470) so all graph copies share one instance:
- thinkingBudget.ts — dashboard Thinking-Budget mode reaches the executor
- backgroundTaskDetector.ts — opt-in background degradation actually fires
- systemTransforms.ts — operator pipeline overrides reach the request path
payloadRules.ts was already safe (lazy per-request DB self-load, #2986).
Guards: thinking-budget-globalthis-5312 + runtime-config-globalthis-5312
(assert globalThis sharing; a module-local let fails them, RED->GREEN).
* refactor(evals): extract built-in golden-set suites from evalRunner.ts (#5740)
Move the 7 static built-in eval suites (golden-set, coding-proficiency,
reasoning-logic, multilingual, safety-guardrails, instruction-following,
codex-comparison) plus the builtInSuites aggregate into the pure-data leaf
src/lib/evals/evalRunner/builtinSuites.ts (zero imports, no side effects).
evalRunner.ts keeps all logic (register/get/list/evaluate/run/scorecard/reset)
and registers the leaf suites at module load, mirroring the original inline
calls. Public API is unchanged (7 exported functions; the suite consts were
already module-private). Host 960->301 LOC; leaf 676 LOC (< 800 cap); host
was frozen-satisfied (961), so this is debt reduction.
Suite data moved verbatim (652 data lines byte-identical). New split-guard
test characterizes the suite ids/case counts/key cases and proves the host
registers every leaf suite at load.
* refactor(models): extract pure transform layer from modelsDevSync.ts (#5743)
Move the models.dev data-model types, the provider-id mapping table
(MODELS_DEV_PROVIDER_MAP + mapProviderId), and the raw->OmniRoute transforms
(transformModelsDevToPricing, transformModelsDevToCapabilities) into the pure
leaf src/lib/modelsDevSync/transform.ts (zero imports, no DB, no module state).
modelsDevSync.ts keeps all sync orchestration, DB access, caches and the
periodic-sync timer; it imports the transforms for internal use and re-exports
mapProviderId/transformModelsDevToPricing/transformModelsDevToCapabilities plus
the ModelCapabilityEntry/CapabilitiesByProvider types, so the public API is
unchanged. Host 924->677 LOC; leaf 279 LOC (< 800 cap); host was
frozen-satisfied (934), so this is debt reduction.
238 moved lines are byte-identical. New split-guard test characterizes the
provider map + both transforms and proves the host re-exports them.
* refactor(resilience): split settings.ts into types + normalize leaves (#5745)
Decompose the (fully pure) resilience settings module into two sibling leaves:
- src/lib/resilience/settings/types.ts: the settings shape (11 public
interfaces + JsonRecord/AuthCategory), zero imports.
- src/lib/resilience/settings/normalize.ts: the coercers (asRecord/toInteger/
toBoolean/feature-flag resolvers) + the 11 per-section normalize* functions.
settings.ts keeps DEFAULT_RESILIENCE_SETTINGS, DEFAULT_REQUEST_QUEUE_MAX_WAIT_MS,
buildLegacyFallback, and the public orchestrators (resolveResilienceSettings,
mergeResilienceSettings, buildLegacyResilienceCompat); it imports the
coercers/normalizers for internal use and re-exports the 11 settings interfaces,
so the public API is unchanged. Host 840->363 LOC; leaves 182 + 359 LOC
(< 800 cap); host was frozen-satisfied (841), so this is debt reduction.
472 moved lines are byte-identical; no cycles (leaves never import the host).
New split-guard test characterizes the coercers/normalizers and the host
resolve/merge/compat orchestration.
* docs(readme): document faster/leaner install — skip native build, sql.js fallback (#5713)
Documents the optional better-sqlite3 + pure-JS fallback chain and OMNIROUTE_SKIP_POSTINSTALL/CI skip flags. Docs-only, claims verified. (#5550)
* feat(compression): T02 opt-in per-engine pipeline circuit-breaker (#5735)
Opt-in, default-off per-engine circuit-breaker for the stacked compression pipeline. Byte-identical to legacy when off. 9 regression tests.
* docs: sync MCP tool count to 95 + routing-strategy count (#5732)
Sync CLAUDE.md/README.md to canonical MCP tool count (95, 35 base) and routing strategies (17). Numbers fact-checked against getAllToolDefinitions()/ROUTING_STRATEGY_VALUES.
* feat(api): add first-class Ollama local provider card (#5712)
First-class ollama-local provider card (localhost:11434/v1, keyless, passthrough models) in LOCAL_PROVIDERS + SELF_HOSTED + default.ts executor case. Docs count 236→237, Local 11→12 (full README sweep). 4 tests. (#5578)
* feat(api): add opt-in API-key provider quota-policy bypass scope (#5731)
Adds an opt-in per-API-key scope (policy:bypass-provider-quota) that lets a key skip provider/account-side quota cutoffs during routing. Operator USD budgets/usage limits still enforced unconditionally (fail-closed, before the bypass). Default-off; UI toggle + badge in API Manager. Integrated into release/v3.8.43.
* feat(codex): opt-in auto-sync of Codex profiles after model discovery (#5737)
Auto-sync ~/.codex/*.config.toml profiles after a provider model sync, reusing the setup-codex generator. Opt-in, default OFF (OMNIROUTE_AUTO_SYNC_CODEX_PROFILES=true; also honors CLI_ALLOW_CONFIG_WRITES). Never touches the active Codex config. Gating test added.
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* feat(providers): opt-in CLI profile auto-sync toggles + Claude Code auto-sync (#5755)
Providers-dashboard 'CLI profile auto-sync' card (Codex + Claude Code toggles), feature-flag backed (default off), + Claude Code auto-sync mirroring the Codex path. Follow-up to #5737.
* feat(compression): T08/H8 (2.3) — graduated CCR retrieval-feedback ramp (#5739)
Turns CCR retrieval feedback from a binary cliff into a graduated ramp: each prior retrieval raises a block's effective minChars linearly (effectiveMinChars); >= 3 retrievals still excluded (Infinity). retrievalRampFactor default 2 (config/env COMPRESSION_CCR_RETRIEVAL_RAMP_FACTOR); 1 = legacy binary. Regression guard: tests/unit/compression/ccr-retrieval-ramp.test.ts (12); 51 existing CCR tests green. gaps v3.8.42 — T08/H8 (2.3).
* feat(compression): T08/H5 (2.4) — usage-observed prefix freeze (opt-in) (#5744)
Evolves the cache-aware guard to also learn which system prompts recur: observed >= threshold → treated as a stable cacheable prefix and preserved even for providers the static check misses. Content-addressed by a hash of the system prompt (OpenAI/Claude/Gemini), in-memory, freeze=preserve (never mutates). Opt-in/default-off (COMPRESSION_PREFIX_FREEZE_ENABLED); respects the never preserve-mode. New prefixFreeze.ts wired into resolveCacheAwareConfig. Regression guard: prefix-freeze.test.ts (10); 44 cache-aware tests green. gaps v3.8.42 — T08/H5 (2.4).
* feat(compression): T08/H7 (2.5) — read-lifecycle engine (collapse superseded reads) (#5754)
New opt-in, default-off read-lifecycle engine: collapses stale/superseded file-Read tool results (same path re-read OR modified later) to a stub, keeping the current Read intact. Anthropic + OpenAI tool shapes; conservative (known tool names, exact path, strictly-later); fail-open. Lossy → opt-in. Regression guard: read-lifecycle.test.ts (10); 41 registry/pipeline suites green. gaps v3.8.42 — T08/H7 (2.5). Completes Onda 2.
* fix(sse): anti-thundering-herd guard tolerates numeric-epoch cooldowns (#5747)
markAccountUnavailable's dedupe guard used a raw `new Date()` on
rateLimitedUntil, which can hold a numeric-epoch string (e.g. the
Antigravity full-quota path via setConnectionRateLimitUntil). That
produced Invalid Date/NaN, so the guard never detected an already
cooling connection — a second concurrent failure on the same
connection overwrote a long quota-exhaustion cooldown with a much
shorter fresh backoff cooldown, making the account selectable again
far sooner than intended.
Reuses the existing cooldownUntilMs normalizer (#3954) instead of a
raw Date parse.
* fix(chat): harden non-streaming SSE aggregation (#5746)
* fix: repoint DashScope/Alibaba setup links to consoles (#5665) (#5762)
* fix: point Quick Start step 1 to API Keys page, not Endpoint (#5695) (#5763)
* fix: onboarding wizard saves providers with unsupported validation (#5692) (#5764)
* docs(security): document full LOCAL_ONLY route set + GHSA-fhh6-4qxv-rpqj + audit path (#5599) (#5748)
Expand ROUTE_GUARD_TIERS.md Tier 1 (LOCAL_ONLY):
- link the GHSA advisory and explain the attack class (RCE via a subprocess spawn
reachable from non-loopback traffic)
- replace the 3-example prefix table with the full LOCAL_ONLY set, mirroring
LOCAL_ONLY_API_PREFIXES / LOCAL_ONLY_API_PATTERNS in routeGuard.ts (the
authoritative source; check-route-guard-membership enforces the code side)
- add an "Operator guidance & auditing" section for users behind
nginx/Cloudflare/Tailscale: don't forge X-Forwarded-For loopback, keep the
manage-scope bypass minimal, and how to audit non-loopback access
Docs-only; SECURITY.md already links here.
Closes #5599
* docs(security): document banned-keyword / account-ban detection (#5600) (#5756)
* docs(security): add BAN_DETECTION.md — banned-keyword / account-ban detection (#5600)
New docs/security/BAN_DETECTION.md documenting the previously-undocumented system:
- the 8 built-in ACCOUNT_DEACTIVATED_SIGNALS + custom keywords are additive
- detection flow (body substring match -> terminal `banned` state, skipped in
account selection; `deactivated` on 401/403; autoDisableBannedAccounts)
- scope: global (all providers); the signal strings target OAuth/subscription scrapers
- custom keywords: add path, 200-char cap, hot-reload, and the false-positive
warning (raw substring match -> prefer full ban sentences, not "quota"/"limit")
- recovery: terminal states never auto-recover -> re-test / re-auth / re-enable
Registered in security meta.json; cross-linked from RESILIENCE_GUIDE (terminal
states). Docs-only.
Closes #5600
* docs(security): clarify deactivated vs expired terminal-status split (#5600)
The same ACCOUNT_DEACTIVATED signal surfaces as two different terminal
statuses depending on the code path: chatCore.ts inline writes 'deactivated'
(401/403 via classifyProviderError), while markAccountUnavailable() ->
resolveTerminalConnectionStatus() writes 'expired'. Document both.
* fix: surface relay proxy-test errors instead of silent failure (#5716) (#5765)
* refactor(api): extract pure discovery leaves from provider-models route (#5758)
Split src/app/api/providers/[id]/models/route.ts (2511 -> 1818 LOC) by moving
the cohesive, DB-free discovery building blocks into four leaves under
discovery/:
- helpers.ts record/string coercion, Azure + base-url helpers,
bearer/named-openai header builders
- normalizers.ts Antigravity / DataRobot / OpenAI-like / SAP models
response normalizers
- providerModelsConfig.ts PROVIDER_MODELS_CONFIG + ProviderModelsConfigEntry
- providerSets.ts NAMED_OPENAI_STYLE_PROVIDERS + isNamedOpenAIStyleProvider
The host keeps all request orchestration and imports the leaves back. The moved
symbols were module-private, so the route's public export set (GET) is unchanged
and no external importer needs updating. Bodies are byte-identical: the code-line
multiset of host + leaves equals the original route verbatim.
Tests:
- repoint the qwen-web source-guard in catalog-updates-v3829-kimi-qwen to the new
config leaf (assertions unchanged)
- add provider-models-discovery-split as the split regression guard (leaf public
surface + host wiring + the #5570 cablyai->aimlapi entry swap)
* fix(memory): enabling Qdrant activates it as the engine + inline guidance (#5597) (#5741)
* fix(memory): enabling Qdrant now activates it as the engine + inline guidance (#5597)
Enabling Qdrant in the Engine tab was inert: retrieval only routes to Qdrant when
memoryVectorStore === "qdrant" (the default "auto" never selects it), and the card
only wrote qdrantEnabled — nothing set the engine selector, and there is no UI for
it. So users configured Qdrant, saw "enabled", but it was never actually used.
- PUT /api/settings/qdrant now sets memoryVectorStore alongside the toggle:
enable -> "qdrant", disable -> "auto". Editing other fields leaves it untouched.
- Add inline guidance to QdrantConfigCard: a Tier-1-vs-Tier-2 banner + per-field
help (host, collection, embedding model). Note there is no "vector dimension" or
"distance metric" field: dimension is auto-detected from the embedder, distance
is always Cosine.
- Document the real behavior in MEMORY.md: engine gate, no back-fill of existing
memories, dimension auto-detect, Cosine-only, API-key-only auth.
Tests: tests/integration/qdrant-routes.test.ts — enable->qdrant, disable->auto, and
field-edit-without-enabled leaves the engine untouched (TDD: red -> green).
Closes #5597
* fix(memory): invalidate memory-settings cache on Qdrant toggle (#5597)
The PUT handler wrote memoryVectorStore to the DB but retrieval reads through
getMemorySettings(), a module-level cache. Without busting it, the engine switch
did not take effect until a process restart (the DB said qdrant, retrieval kept
routing to sqlite-vec). Now calls invalidateMemorySettingsCache() after the write,
mirroring src/app/api/settings/memory/route.ts.
Regression test warms the cache, toggles via the route, and asserts
getMemorySettings().vectorStore flips to qdrant (fails without the invalidate call).
* fix(compression): record Context Editing telemetry on the streaming path (#5761)
Streaming SSE responses now preserve context_management from the final message_delta snapshot and fire the telemetry hook in onStreamComplete, so context-clear savings surface in compression analytics for streaming (not just non-streaming). Additive telemetry, Claude-only, opt-in-neutral. gaps v3.8.42 — T01 (5.1). Test: context-editing-streaming-telemetry.test.ts (3, failing->passing).
* Persist batch item checkpoints during recovery (#5753)
* fix(sse): checkpoint batch item recovery
* fix(db): renumber batch checkpoints migration 110→112 (collision with #5667)
110 was taken by 110_model_context_overrides.sql (#5667), which landed on the
release branch after this PR branched. migrationRunner throws a hard version-
collision error on startup when two files share a numeric prefix. 112 is the
next free slot (110/111 taken on the release tip).
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
---------
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* fix: resolve CCR MCP retrieve principal from api-key auth context (#5649) (#5768)
* feat(cli): show version in startup banner (integrates #5752) (#5769)
* feat(cli): show version in startup banner
Print dim 'v<version>' line below ASCII art logo in omniroute serve.
Uses readFileSync (same pattern as program.mjs) to read package.json.
Closes #5749.
* test(cli): guard startup-banner version line (#5752)
Source-inspection test (same pattern as cli-serve-port.test.ts) asserting
serve.mjs parses the version from package.json and prints v${_pkg.version}
in the startup banner — satisfies Hard Rule #8 for the bin/ change.
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* docs(changelog): credit #5752 startup-banner version line (thanks @chirag127)
---------
Co-authored-by: Chirag Singhal <76880977+chirag127@users.noreply.github.com>
* fix(proxyfetch): skip fallback for non-replayable bodies (#5770)
* chore(release): open v3.8.42 cycle
Bump version to 3.8.42, add CHANGELOG placeholder, sync openapi/electron/open-sse + 42 i18n CHANGELOG mirrors.
* chore: remove unused qdrant schema aliases (#5404)
Integrated into release/v3.8.42
* chore: remove unused memory schema aliases (#5403)
Integrated into release/v3.8.42
* chore: remove unused quota schema types (#5402)
Integrated into release/v3.8.42
* chore: remove unused playground row type (#5401)
Integrated into release/v3.8.42
* chore: remove unused codegraph exports (#5400)
Integrated into release/v3.8.42
* chore: remove unused notion client type (#5399)
Integrated into release/v3.8.42
* chore: remove unused settings types (#5398)
Integrated into release/v3.8.42
* chore: remove unused combo types (#5396)
Integrated into release/v3.8.42
* chore: remove unused provider types (#5393)
Integrated into release/v3.8.42
* chore: remove unused skillssh skill type (#5392)
Integrated into release/v3.8.42
* chore: remove unused status hex key type (#5391)
Integrated into release/v3.8.42
* chore: remove unused batch provider type (#5390)
Integrated into release/v3.8.42
* chore: remove unused skills schema types (#5389)
Integrated into release/v3.8.42
* chore: remove unused codex auth input type (#5388)
Integrated into release/v3.8.42
* chore: remove unused memory schema types (#5387)
Integrated into release/v3.8.42
* chore: remove unused playground row type (#5386)
Integrated into release/v3.8.42
* chore: remove unused qdrant schema types (#5385)
Integrated into release/v3.8.42
* chore: remove unused kiro social schema (#5384)
Integrated into release/v3.8.42
* chore: remove unused memory schema types (#5383)
Integrated into release/v3.8.42
* chore: remove unused audit action type (#5382)
Integrated into release/v3.8.42
* chore: remove unused agent skills schema types (#5381)
Integrated into release/v3.8.42
* chore: remove unused shared logger default export (#5380)
Integrated into release/v3.8.42
* chore: remove unused sse logger helpers (#5378)
Integrated into release/v3.8.42
* chore: remove unused sse model legacy helpers (#5377)
Integrated into release/v3.8.42
* chore: remove unused v1 search response schema (#5376)
Integrated into release/v3.8.42
* chore: remove unused cloud agent result schemas (#5375)
Integrated into release/v3.8.42
* chore: remove unused a2a routing logger readers (#5374)
Integrated into release/v3.8.42
* chore: remove unused webhook delivery detail export (#5372)
Integrated into release/v3.8.42
* chore: remove unused api key type (#5395)
Integrated into release/v3.8.42
* chore: remove unused usage types (#5397)
Integrated into release/v3.8.42
* chore: remove unused cloud agent input types (#5373)
Integrated into release/v3.8.42
* deps: bump electron from 42.4.1 to 42.5.1 in /electron (#5413)
Integrated into release/v3.8.42
* deps: bump the production group with 11 updates (#5414)
Integrated into release/v3.8.42
* fix: frame non-streaming JSON responses (#5416)
Integrated into release/v3.8.42
* fix(services): runNpm shell on win32 + prefix via env for Node 24 EINVAL (#5379) (#5474)
Node 24 refuses execFile of npm.cmd without a shell (nodejs/node#52554),
so embedded-service install (9Router/CLIProxy) failed with spawn EINVAL on
Windows. runNpm now enables shell on win32 only; to stay Hard-Rule-#13 safe
under a shell, the install --prefix is passed via npm_config_prefix (env)
instead of an argv path (survives spaces), and the user-supplied version is
constrained by SERVICE_VERSION_PATTERN at the route boundary.
* fix(cli): restore dist/tls-options.mjs to npm tarball (#5452) (#5503)
Closes #5452
* fix(dashboard): render onboarding wizard on /providers/new (#5427) (#5505)
Closes #5427
* fix(db): EBUSY-safe database import on Windows (#5406) (#5507)
Closes #5406
* chore: remove unused gamification streak exports (#5463)
* chore: remove unused headroom log tail export (#5464)
* chore(dead-code): remove unused prompt cache control helper (#5466)
* chore(duplication): share vscode metadata helpers (#5471)
* chore(duplication): share auth zip extractors (#5475)
* chore(duplication): share vscode tokenized request helper (#5479)
* chore(duplication): share quota strategy ranking helpers (#5482)
* chore(duplication): share recharts donut card (#5484)
* chore(duplication): share provider specific validation (#5485)
* chore(duplication): share batch response formatter (#5488)
* chore(duplication): share redis runtime helpers (#5490)
* chore(duplication): share version manager request parsing (#5492)
* chore(duplication): share media generation route helpers (#5493)
* chore(duplication): share settings transform schemas (#5496)
* chore(duplication): share relay stream finalizer (#5497)
* chore(duplication): share machine id fallback (#5498)
* chore(duplication): share node sqlite adapter (#5500)
* fix: treat terminal stream cancels as complete (#5491)
* fix post-merge ci regressions (#5467)
* fix: gate claude adaptive thinking defaults (#5480)
Co-authored-by: KooshaPari <koosha@example.com>
* fix(fallback): normalize provider error rule headers (#5473)
Co-authored-by: KooshaPari <koosha@example.com>
* fix(rate-limit): normalize queue refresh settings (#5499)
Co-authored-by: KooshaPari <koosha@example.com>
* chore(ci): add npm fetch-retry + release-freeze protocol (Hard Rule #21) (#5506)
- .npmrc: bump fetch-retries 2->5 with backoff so transient registry ECONNRESET during npm ci (electron-release, v3.8.41) retries instead of failing the job; applies repo-wide.
- CLAUDE.md Hard Rule #21: release-freeze coordination marker (label release-freeze) that campaign workflows honor before merging into the active release branch, preventing the mid-release commit races that forced CHANGELOG re-reconciliation in v3.8.40/v3.8.41.
* chore(duplication): share service install helpers (#5495)
Share service install helpers; re-add SERVICE_VERSION_PATTERN regex to the shared schema (dropped in extraction, #5474) + tests rejecting malformed versions.
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* chore(duplication): share proxy route handlers (#5472)
Share proxy route handlers; add resolveProxyLookupResponse regression test (3 branches + custom whereUsed param name).
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* chore(duplication): share combo builder model options (#5477)
Share combo builder model options; add regression test locking custom-model source classification (manual->custom, api-sync->imported).
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* chore(dead-code): ratchet dead code baseline (#5468)
Ratchet dead-code baseline to the true measured value (310 -> 225) after the v3.8.42 dead-code + duplication wave. Measured by check-dead-code.mjs on the tip.
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* fix(dashboard): provider-add UX — i18n labels, surface import warning, default key name (#5511)
* fix(dashboard): provider-add UX — real i18n labels, surface import warning, default key name (#5421 #5428 #5429 #5431 #5435)
Three rough edges in the Add-API-Key / model-import flow, all from the
provider-catalog audit:
1. Validation Model + Account ID form fields shipped untranslated i18n
stub copy ('Validation Model Id Label', etc.) that rendered verbatim.
Replaced with real copy in en.json.
2. Model import silently fell back to the cached/local catalog — the route
returns a 'warning' field the import hook never read. New pure helper
extractImportWarning surfaces it as a log line.
3. Required connection-name field defaulted to '' (let browser autofill
inject garbage like 'wiw'); now defaults to 'main'.
Regression guard: tests/unit/provider-add-ux-i18n-import-warning.test.ts.
* fix(dashboard): compress AddApiKeyModal comment to keep file under frozen size cap
* fix(providers): align Muse Spark (Meta AI) cookie copy to ecto_1_sess (#5449) (#5513)
* fix(providers): align Muse Spark (Meta AI) cookie copy to ecto_1_sess (#5449)
The default Meta AI session cookie migrated from the retired abra_sess to
ecto_1_sess (META_AI_DEFAULT_COOKIE), but the provider form hint and one
401 auth-failure message still named abra_sess, telling users to paste a
cookie that no longer exists. Both strings now name ecto_1_sess.
Regression guard: tests/unit/muse-spark-cookie-copy-5449.test.ts.
* chore: reconcile CHANGELOG with release (keep #5449 + #5511 bullets)
* fix(providers): correct FriendliAI (serverless) + Novita (/openai/v1) endpoints (#5430 #5455) (#5515)
* fix(providers): correct FriendliAI (serverless) and Novita (/openai/v1) endpoints (#5430 #5455)
Both rejected valid keys, verified live with real provider keys:
- FriendliAI baseUrl was /dedicated/v1/... which 403s a serverless flp_* token;
switched to /serverless/v1/... + serverless modelsUrl.
- Novita baseUrl was the legacy /v3/... with a typo'd model id ai-ai/...
(both 404); switched to OpenAI-compat /openai/v1/... + meta-llama/llama-3.1-8b-instruct.
Regression guard: tests/unit/provider-endpoints-friendliai-novita.test.ts.
* chore: reconcile CHANGELOG with release (keep #5430/#5455 + prior bullets)
* fix(providers): gate import for tool-only providers + sanitize Coze validation error (#5420 #5426) (#5522)
#5420: the 'Import Models' button now hides for tool-only providers
(web search / web fetch) via a capability check over resolved serviceKinds,
not just the -search suffix — firecrawl/jina-reader (webFetch) no longer
show an Import button that 400s. No LLM/media provider is affected.
#5426: Coze key validation no longer leaks the raw upstream envelope
({code,msg,logId,from}) into the UI; the Coze error becomes a friendly
message, scoped to provider === 'coze' so no other provider is affected.
Regression guards: tests/unit/model-listing-capability-5420.test.ts,
tests/unit/coze-validation-error-5426.test.ts.
* fix(providers): correct LongCat free tier — GA LongCat-2.0, one-time 10M (KYC) (#5508)
LongCat's preview ended and the Flash-* line was retired (2026-05-29);
the API now exposes only the GA LongCat-2.0 (1M context, 128K output).
The free tier is a ONE-TIME 10M-token grant unlocked after account
signup + KYC verification — NOT a recurring daily/monthly allowance.
The catalog still described the retired preview/Flash models and a
recurring 150M / 5M-per-day budget; this corrects every reference.
Config / code:
- registry/longcat: model LongCat-2.0-Preview -> LongCat-2.0, name +
comment reflect one-time 10M (KYC) and pay-as-you-go beyond it.
- freeModelCatalog: longcat-2.0-preview (150M, recurring-daily) ->
LongCat-2.0 (10M, freeType one-time-initial via creditTokens).
- freeTierCatalog: drop longcat from the recurring-monthly budget map
(one-time credits are excluded by that catalog's own rule).
- regional.ts freeNote: one-time 10M after signup + KYC, not recurring.
- providerCostData: longcat-flash-lite -> longcat-2.0 (pay-as-you-go
0.75/2.95 per 1M, 10M free quota).
- validation probe model longcat -> LongCat-2.0.
Tests:
- free-tier-catalog: longcat now absent from FREE_TIER_BUDGETS;
providerCount 22->21 (clean 21->20); documented total ~1.39B.
- tierResolver: sample model flash-lite -> LongCat-2.0.
Docs:
- README, PROVIDERS-GUIDE, FREE-TIERS-GUIDE, FREE_TIERS: 50M/day
Flash-Lite -> one-time 10M LongCat-2.0 (KYC); 'No auth' -> API key + KYC.
- Regenerated PROVIDER_REFERENCE.md (picks up the new freeNote).
typecheck:core clean; changed-file lint 0 errors; docs-sync PASS.
* fix(providers): Bytez OpenAI-compat base URL + auth-only key validation (#5422) (#5528)
Bytez IS OpenAI-compatible at .../models/v2/openai/v1, but the registry
stored the bare .../models/v2 base, so validation's chat-probe hit
.../models/v2/chat/completions -> 404 -> 'endpoint not supported'.
Part A: registry baseUrl -> full OpenAI-compat chat path.
Part B: a Bytez account only serves catalog-provisioned models, so chat-probe
validation 404s even for valid keys. validateBytezProvider instead probes the
auth-only GET .../models/v2/list/tasks (200=valid, 401/403=invalid).
Verified live with a real key: list/tasks -> 200 (valid) / 401 (invalid).
Regression guard: tests/unit/bytez-validation-5422.test.ts.
* fix(providers): remove dead Phind provider + dedupe HuggingChat catalog listing (#5530)
Integrated into release/v3.8.42 (round 3). Dead Phind removal + HuggingChat dedupe, verified complete.
* fix: protect dynamic dashboard tests with CSRF (#5405)
Integrated into release/v3.8.42 (round 3). Reworked CSRF (HMAC-signed synchronized token).
* docs: clarify bifrost relay backend envs (#5520)
Integrated into release/v3.8.42 (round 3). Doc-only: bifrost relay envs.
* test(quota): guard Claude-Code identity version lockstep (Phase 2) (#5514)
Integrated into release/v3.8.42 (round 3). Claude-Code identity version lockstep guard.
* feat(compression): T02 — honest default-on pipeline inflation guard (H1) (#5527)
Integrated into release/v3.8.42 (round 3). T02 pipeline inflation guard
* feat(compression): T05/C2 — caveman dedup + ultra packs for de, fr, ja (#5529)
Integrated into release/v3.8.42 (round 3). T05/C2 caveman packs de/fr/ja
* feat(compression): T05/C6 — Chinese (zh / wenyan) caveman pack + detection (#5532)
Integrated into release/v3.8.42 (round 3). T05/C6 zh/wenyan pack + detection
* feat(compression): T07/R9 — gradle + dotnet RTK catalog filters (#5537)
Integrated into release/v3.8.42 (round 3). T07/R9 RTK gradle+dotnet filters
* refactor(dashboard): T11 — drop duplicate caveman on/off toggle from the compression settings tab (#5524)
Integrated into release/v3.8.42 (round 3). T11 consolidate duplicate caveman controls; i18n'd the panel hint string (source key).
* test relay routing fallback headers (#5526)
Integrated into release/v3.8.42 (round 3). Relay fallback header extraction + tests (drift-shed: dependabot #5415 commit dropped).
* fix(opencode-plugin): bump to 0.2.0 + auto-publish on release (#5363)
- Bump @omniroute/opencode-plugin from 0.1.0 to 0.2.0 so CI publishes
the accumulated fixes (auto combos, schema fields, debug logging) that
were merged after the initial 0.1.0 publish on May 24.
- Add auto-bump step in npm-publish.yml: detects if the plugin dir
changed since the last release tag and auto-increments patch version,
so the plugin never falls behind again on future releases.
Co-authored-by: herjarsa <herjarsa@users.noreply.github.com>
* [codex] add bifrost auto fallback cooldown (#5519)
Integrated into release/v3.8.42 (round 3). Bifrost auto fallback cooldown; header reconciled with #5526 helper + env-doc.
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* fix onboarding schema client import (#5525)
Integrated into release/v3.8.42 (round 3). Browser-safe onboarding schema import (drift-shed: dependabot #5415 dropped).
* docs: add relay backend strategy guide (#5547)
Port #5533 relay strategy guide to release/v3.8.42 (doc-only).
* fix(chatgpt-web): support GPT-5.5 Pro handoff (#5536)
Integrated into release/v3.8.42 (round 3). GPT-5.5 Pro async stream_handoff support (drift-shed: dependabot #5415 dropped).
* fix(providers): persist Configured filter across page reloads (#5510)
Integrated into release/v3.8.42 (round 3). Persist Configured filter across reloads; extracted shouldSyncProviderDisplayMode race guard + TDD test (Closes #4059).
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* fix(mimocode): route per-account traffic through SOCKS5 proxy dispatchers (#5521)
Integrated into release/v3.8.42 (round 3). Per-account SOCKS5 dispatcher routing — completes #3837's stored proxy config with the actual undici dispatcher layer. Rebased onto .42 (dropped the CI-workflow-deletion commits; merged proxyUrlMap dispatch with #3837's acct.proxy storage).
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
* fix(chatgpt-web): portable SHA3-512 for sentinel PoW under Electron/BoringSSL (#5531) (#5540)
* fix(build): keep ioredis out of the client/CLI bundle via SPAWN_CAPABLE_PREFIXES leaf (#5546)
Fix the dast-smoke ioredis client-bundle regression (proven: dast-smoke green). Remaining reds are pre-existing base-reds/flakes (base.ts file-size, GOLDEN provider drift, shard-1 compression flakes) inherited by all PRs — not from this change.
* chore(release): finalize v3.8.42 CHANGELOG + cycle-close reconciliation
- Reconcile CHANGELOG.md for v3.8.42: 40 bullets covering all 89 commits
since v3.8.41 (4 features, 26 fixes, 10 maintenance incl. 2 rollups for
the 35-PR dead-code sweep + 17-PR DRY consolidation), dedup the merge-
artifact duplicate New Features headers, set release date 2026-06-30.
- Sync 42 docs/i18n/*/CHANGELOG.md mirrors.
- Document 3 new chatgpt-web/TLS env vars in .env.example + ENVIRONMENT.md
(OMNIROUTE_CGPT_WEB_PRO_TIMEOUT_MS, _PRO_POLL_INTERVAL_MS,
OMNIROUTE_CHATGPT_STREAM_FIRST_BYTE_TIMEOUT_MS).
- Cycle-close ratchet rebaselines: eslintWarnings 4116->4121, file-size
base.ts/chatgpt-web.ts/strategySelector.ts/chatgpt-web.test.ts (all
inherited drift, justified inline).
- Regenerate provider translate-path golden snapshot for the merged
bytez/friendliai/novita endpoint fixes.
* chore(changelog): cover #5415 dev-deps bump merged from main
The release/v3.8.42 ↔ main merge (
|
||
|---|---|---|
| .. | ||
| opencode-plugin | ||
| opencode-provider | ||