@oh-my-pi/pi-mnemopi 17.2.10 → 17.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/types/core/embeddings.d.ts +18 -0
- package/package.json +5 -5
- package/src/core/embeddings.ts +38 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [17.2.11] - 2026-08-07
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed an issue where an interrupted local embedding model download could permanently corrupt the cache and silently disable semantic recall. The system now automatically detects incomplete model files, clears the corrupted cache, and retries the download.
|
|
10
|
+
|
|
5
11
|
## [17.2.10] - 2026-08-06
|
|
6
12
|
|
|
7
13
|
### Changed
|
|
@@ -31,6 +31,24 @@ export type LocalModelInitializer = (options: LocalModelInitOptions) => Promise<
|
|
|
31
31
|
* @internal exported for tests
|
|
32
32
|
*/
|
|
33
33
|
export declare function quarantineCorruptModelFile(message: string, cacheDir?: string): Promise<boolean>;
|
|
34
|
+
/**
|
|
35
|
+
* Recover from a partially-extracted fastembed model cache. An interrupted
|
|
36
|
+
* archive download/extraction leaves `<cacheDir>/<model>/` populated with
|
|
37
|
+
* sidecars and a truncated `model.onnx_data` but WITHOUT the graph file
|
|
38
|
+
* (`model.onnx` / `model_optimized.onnx`), so `FlagEmbedding.init` throws
|
|
39
|
+
* `Model file not found at .../model.onnx`. Upstream `retrieveModel`
|
|
40
|
+
* short-circuits on the existing model dir and never re-downloads, and
|
|
41
|
+
* `downloadFileFromGCS` reuses a leftover partial `<model>.tar.gz` as-is, so
|
|
42
|
+
* the cache is stuck broken forever: recall silently dies and the rebuild
|
|
43
|
+
* queue grows every session. Delete the incomplete model dir AND the leftover
|
|
44
|
+
* partial archive so the retry re-downloads from scratch. The model path is
|
|
45
|
+
* error-message CONTENT, so the dir is only removed when it is a direct child
|
|
46
|
+
* of the fastembed cache root — never touch a directory a dependency merely
|
|
47
|
+
* names. Returns true when a retry is worth attempting (the incomplete cache
|
|
48
|
+
* was cleared, or already gone from a concurrent heal).
|
|
49
|
+
* @internal exported for tests
|
|
50
|
+
*/
|
|
51
|
+
export declare function clearIncompleteModelCache(message: string, cacheDir?: string): Promise<boolean>;
|
|
34
52
|
/**
|
|
35
53
|
* Shared local-model initializer: FlagEmbedding.init with BOTH cache heals.
|
|
36
54
|
* Missing sidecars (config/tokenizer/tokens map) re-fetch and retry; a
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-mnemopi",
|
|
4
|
-
"version": "17.2.
|
|
4
|
+
"version": "17.2.12",
|
|
5
5
|
"description": "Local SQLite memory engine for Oh My Pi agents",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"fmt": "biome format --write ."
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@oh-my-pi/pi-ai": "17.2.
|
|
43
|
-
"@oh-my-pi/pi-catalog": "17.2.
|
|
44
|
-
"@oh-my-pi/pi-natives": "17.2.
|
|
45
|
-
"@oh-my-pi/pi-utils": "17.2.
|
|
42
|
+
"@oh-my-pi/pi-ai": "17.2.12",
|
|
43
|
+
"@oh-my-pi/pi-catalog": "17.2.12",
|
|
44
|
+
"@oh-my-pi/pi-natives": "17.2.12",
|
|
45
|
+
"@oh-my-pi/pi-utils": "17.2.12"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"fastembed": "2.1.0",
|
package/src/core/embeddings.ts
CHANGED
|
@@ -92,6 +92,41 @@ export async function quarantineCorruptModelFile(message: string, cacheDir?: str
|
|
|
92
92
|
return true;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Recover from a partially-extracted fastembed model cache. An interrupted
|
|
97
|
+
* archive download/extraction leaves `<cacheDir>/<model>/` populated with
|
|
98
|
+
* sidecars and a truncated `model.onnx_data` but WITHOUT the graph file
|
|
99
|
+
* (`model.onnx` / `model_optimized.onnx`), so `FlagEmbedding.init` throws
|
|
100
|
+
* `Model file not found at .../model.onnx`. Upstream `retrieveModel`
|
|
101
|
+
* short-circuits on the existing model dir and never re-downloads, and
|
|
102
|
+
* `downloadFileFromGCS` reuses a leftover partial `<model>.tar.gz` as-is, so
|
|
103
|
+
* the cache is stuck broken forever: recall silently dies and the rebuild
|
|
104
|
+
* queue grows every session. Delete the incomplete model dir AND the leftover
|
|
105
|
+
* partial archive so the retry re-downloads from scratch. The model path is
|
|
106
|
+
* error-message CONTENT, so the dir is only removed when it is a direct child
|
|
107
|
+
* of the fastembed cache root — never touch a directory a dependency merely
|
|
108
|
+
* names. Returns true when a retry is worth attempting (the incomplete cache
|
|
109
|
+
* was cleared, or already gone from a concurrent heal).
|
|
110
|
+
* @internal exported for tests
|
|
111
|
+
*/
|
|
112
|
+
export async function clearIncompleteModelCache(message: string, cacheDir?: string): Promise<boolean> {
|
|
113
|
+
const match = /Model file not found at (.+?\.onnx)\b/i.exec(message);
|
|
114
|
+
if (!match) return false;
|
|
115
|
+
const modelFile = nodePath.resolve(match[1]);
|
|
116
|
+
const modelDir = nodePath.dirname(modelFile);
|
|
117
|
+
const cacheRoot = nodePath.resolve(cacheDir ?? getFastembedCacheDir());
|
|
118
|
+
// Only a direct child of the cache root: `<cacheRoot>/<model>`.
|
|
119
|
+
if (nodePath.dirname(modelDir) !== cacheRoot) return false;
|
|
120
|
+
try {
|
|
121
|
+
await fsp.rm(modelDir, { recursive: true, force: true });
|
|
122
|
+
await fsp.rm(`${modelDir}.tar.gz`, { force: true });
|
|
123
|
+
logger.warn("mnemopi: cleared incomplete local embedding model cache; re-downloading", { modelDir });
|
|
124
|
+
} catch {
|
|
125
|
+
// Concurrent heal or vanished dir: the single retry stays safe.
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
95
130
|
const SIDECAR_ERROR_RE =
|
|
96
131
|
/(?:Config file not found at .*config|Tokenizer file not found at .*tokenizer|Tokens map file not found at .*special_tokens_map)/u;
|
|
97
132
|
|
|
@@ -124,6 +159,9 @@ export async function defaultLocalModelInitializer(options: LocalModelInitOption
|
|
|
124
159
|
if (/Protobuf parsing failed/i.test(message) && (await quarantineCorruptModelFile(message, cacheDir))) {
|
|
125
160
|
return initWithSidecarHeal();
|
|
126
161
|
}
|
|
162
|
+
if (await clearIncompleteModelCache(message, cacheDir)) {
|
|
163
|
+
return initWithSidecarHeal();
|
|
164
|
+
}
|
|
127
165
|
throw error;
|
|
128
166
|
}
|
|
129
167
|
}
|