diff --git a/static/index.html b/static/index.html index c0fd60197..34195ca38 100644 --- a/static/index.html +++ b/static/index.html @@ -219,8 +219,8 @@ }, { once: true }); })(); - - + + @@ -2512,7 +2512,7 @@ - + diff --git a/static/js/modelPicker.js b/static/js/modelPicker.js index 12fb3479e..53077b73b 100644 --- a/static/js/modelPicker.js +++ b/static/js/modelPicker.js @@ -92,6 +92,31 @@ function _modelExists(modelId, url) { }); } +function _firstAvailableModel() { + if (!window.modelsModule || !window.modelsModule.getCachedItems) return null; + const items = window.modelsModule.getCachedItems() || []; + for (const item of items) { + if (item.offline) continue; + const models = (item.models || []).concat(item.models_extra || []); + if (!models.length) continue; + return { + url: item.url, + modelId: models[0], + endpointId: item.endpoint_id || '', + }; + } + return null; +} + +async function _ensureModelCacheForFallback() { + if (!window.modelsModule || !window.modelsModule.getCachedItems) return; + const items = window.modelsModule.getCachedItems() || []; + if (items.length) return; + if (typeof window.modelsModule.refreshModels === 'function') { + try { await window.modelsModule.refreshModels(false); } catch (_) {} + } +} + async function _ensureDefaultPendingChat() { if (!_deps || _defaultChatPickInFlight) return; if (_deps.getCurrentSessionId && _deps.getCurrentSessionId()) return; @@ -99,12 +124,13 @@ async function _ensureDefaultPendingChat() { if (pending && pending.modelId) return; _defaultChatPickInFlight = true; try { + await _ensureModelCacheForFallback(); let dc = null; try { const res = await fetch(`${API_BASE}/api/default-chat`, { credentials: 'same-origin' }); if (res.ok) dc = await res.json(); } catch (_) {} - if (dc && dc.endpoint_url && dc.model) { + if (dc && dc.endpoint_url && dc.model && _modelExists(dc.model, dc.endpoint_url)) { _deps.setPendingChat({ url: dc.endpoint_url, modelId: dc.model, @@ -114,15 +140,12 @@ async function _ensureDefaultPendingChat() { updateModelPicker(); return; } - // No configured default: preserve the old convenience fallback. - if (window.modelsModule && window.modelsModule.getCachedItems) { - const items = window.modelsModule.getCachedItems(); - const first = items.find(item => !item.offline && ((item.models || []).length || (item.models_extra || []).length)); - if (first) { - const models = (first.models || []).concat(first.models_extra || []); - _deps.setPendingChat({ url: first.url, modelId: models[0], endpointId: first.endpoint_id }); - updateModelPicker(); - } + // No configured default, or the configured default is gone/offline: + // preserve the convenience fallback and keep the picker usable. + const fallback = _firstAvailableModel(); + if (fallback) { + _deps.setPendingChat(fallback); + updateModelPicker(); } } finally { _defaultChatPickInFlight = false; diff --git a/static/sw.js b/static/sw.js index 8e8930e9d..3df123bce 100644 --- a/static/sw.js +++ b/static/sw.js @@ -7,7 +7,7 @@ // - Other static assets (images/fonts/libs): cache-first with bg refresh. // - API / non-GET: never cached. // Bump CACHE_NAME whenever the precache list or SW logic changes. -const CACHE_NAME = 'odysseus-v333'; +const CACHE_NAME = 'odysseus-v334'; // Core shell precached on install so repeat opens are instant without any // network wait. Keep this list in sync with the