Storage & Persistence¶
Available browser storage APIs¶
| API | Best for | Capacity | Persistence | Async |
|---|---|---|---|---|
| Cache Storage | AI models, large binary assets | Browser-managed (GBs) | Survives restarts | Yes |
| IndexedDB | Structured data, results, history | Browser-managed (GBs) | Survives restarts | Yes |
| OPFS | Large file processing, temp files | Browser-managed (GBs) | Survives restarts | Yes |
| localStorage | Small settings, preferences | 5-10MB | Survives restarts | No (sync) |
| sessionStorage | Temp state within tab | 5-10MB | Tab only | No (sync) |
| File System Access API | Read/write user's local files | Unlimited | User-granted | Yes |
Cache Storage (for AI models)¶
Primary storage for downloaded AI models. This is how bepub caches Kokoro TTS.
// Store a model
const cache = await caches.open('agent-models-v1');
await cache.put(
'https://huggingface.co/onnx-community/whisper-small/resolve/main/model.onnx',
modelResponse
);
// Retrieve cached model
const cached = await cache.match(modelUrl);
if (cached) {
const buffer = await cached.arrayBuffer();
// Load into ONNX runtime
}
Shared model cache across agents¶
If multiple agents need the same model (e.g., Whisper), they can share a cache:
// Model cache service (loaded by Host Worker's service worker)
const SHARED_CACHE = 'fags-shared-models';
async function getOrDownloadModel(modelUrl, onProgress) {
const cache = await caches.open(SHARED_CACHE);
const cached = await cache.match(modelUrl);
if (cached) return cached;
const response = await fetch(modelUrl);
// Clone before caching (response can only be consumed once)
cache.put(modelUrl, response.clone());
return response;
}
IndexedDB (for results and history)¶
Structured storage for agent outputs, user history, preferences.
// Using idb-keyval (lightweight wrapper)
import { get, set, del, keys } from 'idb-keyval';
// Save transcription result
await set(`transcript:${audioHash}`, {
text: transcriptText,
timestamp: Date.now(),
model: 'whisper-small',
duration: audioDuration
});
// Retrieve history
const allKeys = await keys();
const transcriptKeys = allKeys.filter(k => k.startsWith('transcript:'));
OPFS (Origin Private File System)¶
For agents that process large files (video, audio, datasets):
const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle('processing.wav', { create: true });
const writable = await fileHandle.createWritable();
await writable.write(audioData);
await writable.close();
// Read back
const file = await fileHandle.getFile();
const arrayBuffer = await file.arrayBuffer();
OPFS is faster than IndexedDB for large binary files and supports streaming writes.
File System Access API¶
For agents that need to read/write files on the user's machine:
// Open file picker
const [handle] = await window.showOpenFilePicker({
types: [{ description: 'Audio', accept: { 'audio/*': ['.mp3', '.wav', '.m4a'] } }]
});
const file = await handle.getFile();
// Save result
const saveHandle = await window.showSaveFilePicker({
suggestedName: 'transcript.txt',
types: [{ description: 'Text', accept: { 'text/plain': ['.txt'] } }]
});
const writable = await saveHandle.createWritable();
await writable.write(transcriptText);
await writable.close();
Offline support (Service Worker)¶
Agents can work completely offline after first load:
// service-worker.js
const CACHE_NAME = 'agent-shell-v1';
const SHELL_FILES = ['/', '/index.html', '/main.js', '/style.css'];
self.addEventListener('install', (e) => {
e.waitUntil(caches.open(CACHE_NAME).then(c => c.addAll(SHELL_FILES)));
});
self.addEventListener('fetch', (e) => {
e.respondWith(
caches.match(e.request).then(r => r || fetch(e.request))
);
});
Combined with cached AI models in Cache Storage, an agent can: 1. Load instantly (cached shell) 2. Run inference (cached model) 3. Save results (IndexedDB) 4. All without any network connection
Storage budget¶
Browsers manage storage quotas. Typical allowance:
| Browser | Default quota |
|---|---|
| Chrome | 60% of disk space (per origin) |
| Firefox | 50% of disk space (per origin) |
| Safari | 1GB default, prompts for more |
For a 200MB model + app shell + results cache, this is more than enough.
SDK storage helpers¶
// @freeagentstore/sdk
import { useModelCache, useResultStore, useOffline } from '@freeagentstore/sdk/hooks';
function MyAgent() {
// Model management
const { model, loading, progress, cached } = useModelCache('whisper-small');
// Result persistence
const { save, load, history } = useResultStore('transcriptions');
// Offline status
const { isOffline, canWorkOffline } = useOffline();
// ...
}