Booting sequence activated.

This commit is contained in:
Enrico Ros
2024-10-17 14:40:03 -07:00
parent 51fdf2705d
commit 915bc6cc89
5 changed files with 83 additions and 44 deletions
@@ -122,5 +122,6 @@ export async function transferAttachmentOwnedDBAsset({ part }: DMessageAttachmen
* GC Functions for Attachment DBlobs systems: remove leftover drafts
*/
export async function gcAttachmentDBlobs() {
// wipe all objects related to attachment drafts that could have been there from previous sessions
await gcDBAssetsByScope('global', 'attachment-drafts', null, []);
}
+30
View File
@@ -3,6 +3,9 @@ import { persist } from 'zustand/middleware';
import { useShallow } from 'zustand/react/shallow';
import { Release } from '~/common/app.release';
import { estimatePersistentStorageOrThrow, requestPersistentStorageSafe } from '~/common/util/storageUtils';
import { gcAttachmentDBlobs } from '~/common/attachment-drafts/attachment.dblobs';
import { gcChatImageAssets } from '~/common/stores/chat/chat.gc';
import { reconfigureBackendModels } from '~/common/logic/reconfigureBackendModels';
@@ -74,6 +77,33 @@ export async function sherpaReconfigureBackendModels() {
}
// Storage Maintenance & Garbage Collection
export async function sherpaStorageMaintenance() {
// Request persistent storage for the current origin, so that indexedDB's content is not evicted
const persisted = await requestPersistentStorageSafe(); // doesn't throw
if (persisted) {
try {
const usage = await estimatePersistentStorageOrThrow();
if (!usage)
console.warn('Issue requesting persistent storage');
else
console.log('Persistent storage statistics:', usage);
} catch (error) {
console.error('Error estimating persistent storage:', error);
}
}
// GC: Remove chat dblobs (not persisted in chat fragments)
void gcChatImageAssets(); // fire/forget
// GC: Remove old attachment drafts (not persisted in chats)
void gcAttachmentDBlobs(); // fire/forget
}
// Chat Composer Prefill
export const setComposerStartupText = (text: string | null) => {
@@ -4,7 +4,6 @@ import { useKnowledgeOfBackendCaps } from '~/modules/backend/store-backend-capab
import { Release } from '~/common/app.release';
import { apiQuery } from '~/common/util/trpc.client';
import { preloadTiktokenLibrary } from '~/common/tokens/tokens.text';
import { themeFontFamilyCss } from '~/common/app.theme';
@@ -93,7 +92,7 @@ export function ProviderBackendCapabilities(props: { children: React.ReactNode }
if (data) {
storeBackendCapabilities(data);
// Compare client and server build info
// Match frontend and backend versions
const clientBuildInfo = Release.buildInfo('frontend');
const serverBuildInfo = data.build || {};
setVersionVerified(clientBuildInfo.gitSha === serverBuildInfo.gitSha && clientBuildInfo.pkgVersion === serverBuildInfo.pkgVersion);
@@ -101,19 +100,14 @@ export function ProviderBackendCapabilities(props: { children: React.ReactNode }
}, [data, storeBackendCapabilities]);
// [effect] warn if the backend is not available
// [effect] set the timeout flag if waiting too long for the capabilities
React.useEffect(() => {
if (!haveCapabilities) {
const timeout = setTimeout(() => setBackendTimeout(true), BACKEND_WARNING_TIMEOUT);
return () => clearTimeout(timeout);
}
}, [haveCapabilities]);
// [effect] then preload the Tiktoken library right when proceeding to the UI
React.useEffect(() => {
// large WASM payload, so fire/forget
if (haveCapabilities)
void preloadTiktokenLibrary();
if (!haveCapabilities) return;
const timeout = setTimeout(() => setBackendTimeout(true), BACKEND_WARNING_TIMEOUT);
return () => {
clearTimeout(timeout);
setBackendTimeout(false);
};
}, [haveCapabilities]);
+43 -29
View File
@@ -1,13 +1,10 @@
import * as React from 'react';
import { useRouter } from 'next/router';
import { gcAttachmentDBlobs } from '~/common/attachment-drafts/attachment.dblobs';
import { estimatePersistentStorageOrThrow, requestPersistentStorage } from '~/common/util/storageUtils';
import { markNewsAsSeen, shallRedirectToNews, sherpaReconfigureBackendModels } from '~/common/logic/store-logic-sherpa';
import { markNewsAsSeen, shallRedirectToNews, sherpaReconfigureBackendModels, sherpaStorageMaintenance } from '~/common/logic/store-logic-sherpa';
import { navigateToNews, ROUTE_APP_CHAT } from '~/common/app.routes';
import { preloadTiktokenLibrary } from '~/common/tokens/tokens.text';
import { useNextLoadProgress } from '~/common/components/useNextLoadProgress';
import { gcChatImageAssets } from '../stores/chat/chat.gc';
export function ProviderBootstrapLogic(props: { children: React.ReactNode }) {
@@ -23,31 +20,10 @@ export function ProviderBootstrapLogic(props: { children: React.ReactNode }) {
const isOnChat = route === ROUTE_APP_CHAT;
const doRedirectToNews = isOnChat && shallRedirectToNews();
// [autoconf] initiate the llm auto-configuration process if on the chat
const doAutoConf = isOnChat && !doRedirectToNews;
React.useEffect(() => {
doAutoConf && void sherpaReconfigureBackendModels();
}, [doAutoConf]);
// [gc] garbage collection(s)
React.useEffect(() => {
// Request persistent storage for the current origin, so that indexedDB's content is not evicted.
requestPersistentStorage()
.then((persisted: boolean) => persisted ? null : estimatePersistentStorageOrThrow())
.then((usage) => usage ? console.warn('Issue requesting persistent storage; usage:', usage) : null)
.finally(() => {
// GC: Remove chat dblobs (not persisted in chat fragments)
void gcChatImageAssets(); // fire/forget
// GC: Remove old attachment drafts (not persisted in chats)
void gcAttachmentDBlobs(); // fire/forget
});
}, []);
// redirect Chat -> News if fresh news
const isRedirecting = React.useMemo(() => {
const isRedirectingToNews = React.useMemo(() => {
if (doRedirectToNews) {
// the async is important (esp. on strict mode second pass)
navigateToNews().then(() => markNewsAsSeen()).catch(console.error);
return true;
}
@@ -55,5 +31,43 @@ export function ProviderBootstrapLogic(props: { children: React.ReactNode }) {
}, [doRedirectToNews]);
return isRedirecting ? null : props.children;
}
// decide what to launch
const launchPreload = isOnChat && !isRedirectingToNews;
const launchAutoConf = isOnChat && !isRedirectingToNews;
const launchStorageGC = true;
// [preload] kick-off a preload of the Tiktoken library right when proceeding to the UI
React.useEffect(() => {
if (!launchPreload) return;
void preloadTiktokenLibrary(); // fire/forget (large WASM payload)
}, [launchPreload]);
// [autoconf] initiate the llm auto-configuration process if on the chat
React.useEffect(() => {
if (!launchAutoConf) return;
void sherpaReconfigureBackendModels(); // fire/forget (background server-driven model reconfiguration)
}, [launchAutoConf]);
// storage maintenance and garbage collection
React.useEffect(() => {
if (!launchStorageGC) return;
const timeout = setTimeout(sherpaStorageMaintenance, 0);
return () => clearTimeout(timeout);
}, [launchStorageGC]);
//
// Render Gates
//
if (isRedirectingToNews)
return null;
return props.children;
}
+1 -1
View File
@@ -6,7 +6,7 @@ const DEBUG_PERSISTENCE = false;
/**
* Request persistent storage for the current origin, so that indexedDB's content is not evicted.
*/
export async function requestPersistentStorage(): Promise<boolean> {
export async function requestPersistentStorageSafe(): Promise<boolean> {
try {
if (isBrowser && navigator.storage && navigator.storage.persist) {
const isPersisted = await navigator.storage.persisted();