Skip to content

Commit 89c3668

Browse files
committed
Add model version to control cache invalidation
- Version mismatch → delete cache, force re-download (new model) - URL-only change with same version → keep cache, update stored URL - Existing users without a version field get the cache preserved (the `modelData.version &&` guard handles this gracefully) To force all clients to re-download, bump NEXT_PUBLIC_MAIA_MODEL_VERSION (or the hardcoded default in MaiaEngineContext.tsx). https://claude.ai/code/session_01T73Yphu4y2U3c3ctCcHVPf
1 parent e7ab527 commit 89c3668

3 files changed

Lines changed: 36 additions & 12 deletions

File tree

src/contexts/MaiaEngineContext.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export const MaiaEngineContextProvider: React.FC<{ children: ReactNode }> = ({
3434
model:
3535
process.env.NEXT_PUBLIC_MAIA_MODEL_URL ??
3636
'https://raw.githubusercontent.com/CSSLab/maia-platform-frontend/e23a50e/public/maia2/maia_rapid.onnx',
37+
modelVersion: process.env.NEXT_PUBLIC_MAIA_MODEL_VERSION ?? '1',
3738
setStatus: setStatus,
3839
setProgress: setProgress,
3940
setError: setError,

src/lib/engine/maia.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { MaiaModelStorage } from './storage'
66

77
interface MaiaOptions {
88
model: string
9+
modelVersion: string
910
setStatus: (status: MaiaStatus) => void
1011
setProgress: (progress: number) => void
1112
setError: (error: string) => void
@@ -14,11 +15,13 @@ interface MaiaOptions {
1415
class Maia {
1516
private model!: InferenceSession
1617
private modelUrl: string
18+
private modelVersion: string
1719
private options: MaiaOptions
1820
private storage: MaiaModelStorage
1921

2022
constructor(options: MaiaOptions) {
2123
this.modelUrl = options.model
24+
this.modelVersion = options.modelVersion
2225
this.options = options
2326
this.storage = new MaiaModelStorage()
2427

@@ -30,7 +33,7 @@ class Maia {
3033
await this.storage.requestPersistentStorage()
3134

3235
console.log('Attempting to get model from IndexedDB...')
33-
const buffer = await this.storage.getModel(this.modelUrl)
36+
const buffer = await this.storage.getModel(this.modelUrl, this.modelVersion)
3437

3538
if (buffer) {
3639
console.log('Model found in IndexedDB, initializing...')
@@ -94,7 +97,7 @@ class Maia {
9497
position += chunk.length
9598
}
9699

97-
await this.storage.storeModel(this.modelUrl, buffer.buffer)
100+
await this.storage.storeModel(this.modelUrl, this.modelVersion, buffer.buffer)
98101

99102
await this.initializeModel(buffer.buffer)
100103
this.options.setStatus('ready')

src/lib/engine/storage.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
interface ModelStorage {
22
id: string
33
url: string
4+
version: string
45
data: Blob
56
timestamp: number
67
size: number
@@ -34,7 +35,11 @@ export class MaiaModelStorage {
3435
})
3536
}
3637

37-
async storeModel(modelUrl: string, buffer: ArrayBuffer): Promise<void> {
38+
async storeModel(
39+
modelUrl: string,
40+
modelVersion: string,
41+
buffer: ArrayBuffer,
42+
): Promise<void> {
3843
try {
3944
const db = await this.openDB()
4045
const transaction = db.transaction([this.storeName], 'readwrite')
@@ -43,6 +48,7 @@ export class MaiaModelStorage {
4348
const modelData: ModelStorage = {
4449
id: 'maia-rapid-model',
4550
url: modelUrl,
51+
version: modelVersion,
4652
data: new Blob([buffer]),
4753
timestamp: Date.now(),
4854
size: buffer.byteLength,
@@ -61,7 +67,10 @@ export class MaiaModelStorage {
6167
}
6268
}
6369

64-
async getModel(modelUrl: string): Promise<ArrayBuffer | null> {
70+
async getModel(
71+
modelUrl: string,
72+
modelVersion: string,
73+
): Promise<ArrayBuffer | null> {
6574
console.log('Storage: getModel called with URL:', modelUrl)
6675

6776
try {
@@ -95,22 +104,33 @@ export class MaiaModelStorage {
95104
return null
96105
}
97106

98-
// If the URL changed but we still have cached data, keep the model
99-
// and update the stored URL so future loads hit the cache directly.
100-
if (modelData.url !== modelUrl) {
101-
console.log('Storage: Model URL changed, updating stored URL')
102-
console.log('Storage: Cached URL:', modelData.url)
103-
console.log('Storage: New URL:', modelUrl)
107+
// Version mismatch = genuinely new model, must re-download.
108+
if (modelData.version && modelData.version !== modelVersion) {
109+
console.log('Storage: Model version changed, clearing old cache')
110+
console.log('Storage: Cached version:', modelData.version)
111+
console.log('Storage: Required version:', modelVersion)
112+
await this.deleteModel()
113+
return null
114+
}
115+
116+
// URL changed but same version (e.g. moved hosts) — keep the cache,
117+
// just update the stored URL so future loads match immediately.
118+
if (modelData.url !== modelUrl || modelData.version !== modelVersion) {
119+
console.log('Storage: Updating stored URL/version')
104120
try {
105121
const rwTx = db.transaction([this.storeName], 'readwrite')
106122
const rwStore = rwTx.objectStore(this.storeName)
107123
await new Promise<void>((resolve, reject) => {
108-
const req = rwStore.put({ ...modelData, url: modelUrl })
124+
const req = rwStore.put({
125+
...modelData,
126+
url: modelUrl,
127+
version: modelVersion,
128+
})
109129
req.onsuccess = () => resolve()
110130
req.onerror = () => reject(req.error)
111131
})
112132
} catch (e) {
113-
console.warn('Storage: Failed to update stored URL:', e)
133+
console.warn('Storage: Failed to update stored URL/version:', e)
114134
}
115135
}
116136

0 commit comments

Comments
 (0)