* fix(api): stop /v1/models rebuilding the catalog on almost every request
The response cache added by #6408 memoized the serialized body for
`modelCatalogCacheTtlMs`, defaulted to 1500 ms. On a real install the builder
takes far longer than that: measured on the production VPS, ~49 s for a 1.3 MB /
2645-model catalog. Any two requests more than 1.5 s apart therefore both missed
the fresh window, and the second fell into stale-while-revalidate — which
rebuilds via `setTimeout(…, 0)` and, because the builder is overwhelmingly
synchronous under the single-threaded App Router, pins the event loop, so even
the "served immediately" stale body only reaches the client once the rebuild
finishes. Net effect: ~50 s on essentially every call.
Measured on the VPS (1 cold build + 5 sequential requests):
cold = 48.93s
req1 = 3.19s ← the only hit
req2 = 50.51s req3 = 50.93s req4 = 47.43s req5 = 52.28s
Raise the default to 60 s. A short TTL is redundant with the invalidation this
cache already has: `invalidateDbCache()` bumps `modelCatalogCacheVersion` on
every settings/connections/combos/pricing write and
`dropCatalogCacheIfStateChanged()` drops the whole cache the moment it moves, so
post-write freshness never depended on the TTL. What the TTL governs is the
"nothing was written" case, where replaying a body built seconds ago is the
point of the cache. 60 s matches the ceiling the settings schema already allows
for the override, so the default can never exceed what an operator may configure.
The value that actually takes effect is the settings default, not the constant:
`catalog.ts` resolves `dbSettings.cache?.modelCatalogCacheTtlMs ??
CATALOG_CACHE_TTL_MS_DEFAULT`, and the `??` never falls through while a settings
default is declared. Raising only the constant is a silent no-op — which is how
the first attempt at this fix measured identical to no fix at all. All three
declarations are aligned and a test pins them together.
* docs(changelog): add fragment for #8833
---------
Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
* feat(settings): configurable model catalog cache TTL
Add modelCatalogCacheTtlMs to DatabaseSettings with default 1500ms.
Extend cache-config API route to accept the new field.
Replace hardcoded catalog cache TTL with dynamic settings value.
Add 'Cache' settings tab at /dashboard/settings/cache with sidebar entry,
i18n keys, header description, and legacy route redirect.
* feat(combo): add model connection filter toggle to ModelSelectModal
Adds a 'Show configured only' checkbox below the search bar in
ModelSelectModal that filters each provider group's models through
hasEligibleConnectionForModel. Toggle state persists in localStorage.
- Import hasEligibleConnectionForModel from domain/connectionModelRules
- showConfiguredOnly state + localStorage persistence
- connectionFilteredGroups memo layered on filteredGroups
- Renders both provider section and empty state from connectionFilteredGroups
* test(combo): add connection filter toggle tests for ModelSelectModal
Three test cases: (1) hide excluded models when toggle on,
(2) show empty state when all models excluded,
(3) drop provider group when all its models excluded.
All 3 tests pass.
* fix(settings): correct cache-config route import + add route/tab coverage
The cache-config route imported get/update helpers from a nonexistent
module (@/lib/localDb/databaseSettings) and called an undefined
updateSettings() in PUT, crashing every request. Import the real
databaseSettings module (matching the sibling database/route.ts
convention) and call updateDatabaseSettings(); idempotencyWindowMs is
routed through the flat @/lib/db/settings module instead, since that is
where it is actually read at runtime (idempotencyLayer.ts,
runtimeSettings.ts) — it was never part of the databaseSettings "cache"
section type.
Also fixes a dashboard-typecheck regression in ModelSelectModal.tsx: the
new connection-filter toggle called hasEligibleConnectionForModel() with
activeProviders entries typed too narrowly to include
providerSpecificData, which real connection objects carry at runtime.
Adds:
- tests/unit/cache-config-route-8219.test.ts: GET/PUT resolve without
crashing, modelCatalogCacheTtlMs and idempotencyWindowMs round-trip.
- tests/unit/ui/cache-settings-tab-bounds-8219.test.tsx: CacheSettingsTab
min/max TTL bounds (100ms/60000ms) gate the Save button and surface a
validation message; in-bounds values PUT correctly.
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
* chore(quality): rebaseline sections.ts for #8219 own-growth
---------
Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>