@o-lang/semantic-doc-search 1.0.30 → 1.0.31
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/package.json +1 -1
- package/src/embeddings/local.js +9 -10
- package/src/resolver.js +18 -5
package/package.json
CHANGED
package/src/embeddings/local.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - No silent failures
|
|
7
7
|
* - No zero vectors
|
|
8
8
|
* - Deterministic behavior
|
|
9
|
-
* - DEFENSIVE against method detaching
|
|
9
|
+
* - DEFENSIVE against method detaching & invalid vectors
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
class LocalEmbedding {
|
|
@@ -15,7 +15,7 @@ class LocalEmbedding {
|
|
|
15
15
|
this.model = null;
|
|
16
16
|
this.loading = null;
|
|
17
17
|
|
|
18
|
-
// 🔒
|
|
18
|
+
// 🔒 Bind methods to prevent resolver breakage
|
|
19
19
|
this.loadModel = this.loadModel.bind(this);
|
|
20
20
|
this.embed = this.embed.bind(this);
|
|
21
21
|
this.embedBatch = this.embedBatch.bind(this);
|
|
@@ -73,18 +73,19 @@ class LocalEmbedding {
|
|
|
73
73
|
normalize: true,
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
// ✅ Defensive: ensure vector is a valid array
|
|
77
|
+
const vector = Array.isArray(output?.data) ? Array.from(output.data) : null;
|
|
77
78
|
|
|
78
|
-
if (vector.length !== this.dim) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
);
|
|
79
|
+
if (!Array.isArray(vector) || vector.length !== this.dim) {
|
|
80
|
+
console.error("❌ Invalid embedding vector returned:", vector);
|
|
81
|
+
throw new Error(`Invalid embedding dimension: ${vector?.length || 0} (expected ${this.dim})`);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
return vector;
|
|
85
85
|
} catch (err) {
|
|
86
86
|
console.error(
|
|
87
|
-
`❌ Embedding failed for text: "${text.slice(0, 60)}..."
|
|
87
|
+
`❌ Embedding failed for text: "${text.slice(0, 60)}..."`,
|
|
88
|
+
err
|
|
88
89
|
);
|
|
89
90
|
throw err;
|
|
90
91
|
}
|
|
@@ -115,7 +116,5 @@ class LocalEmbedding {
|
|
|
115
116
|
|
|
116
117
|
/* ---------------- SINGLETON EXPORT ---------------- */
|
|
117
118
|
|
|
118
|
-
// One embedder per process (CRITICAL)
|
|
119
119
|
const embedder = new LocalEmbedding();
|
|
120
|
-
|
|
121
120
|
module.exports = embedder;
|
package/src/resolver.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const VectorRouter = require("./adapters/vectorRouter");
|
|
2
|
-
const
|
|
2
|
+
const embedder = require("./embeddings/local"); // ✅ singleton embedder
|
|
3
3
|
const { extractQuery } = require("./utils/extractQuery");
|
|
4
4
|
const { formatResults } = require("./utils/formatResults");
|
|
5
5
|
const fs = require("fs");
|
|
@@ -17,11 +17,13 @@ function loadCache() {
|
|
|
17
17
|
} catch {}
|
|
18
18
|
return {};
|
|
19
19
|
}
|
|
20
|
+
|
|
20
21
|
function saveCache(cache) {
|
|
21
22
|
try {
|
|
22
23
|
fs.writeFileSync(CACHE_PATH, JSON.stringify(cache, null, 2));
|
|
23
24
|
} catch {}
|
|
24
25
|
}
|
|
26
|
+
|
|
25
27
|
function hashContent(str) {
|
|
26
28
|
return crypto.createHash("sha256").update(str).digest("hex");
|
|
27
29
|
}
|
|
@@ -64,8 +66,13 @@ async function resolver(action, context = {}) {
|
|
|
64
66
|
const hash = hashContent(text);
|
|
65
67
|
if (cache[hash]) continue; // Skip already ingested
|
|
66
68
|
|
|
67
|
-
const vector = await embed(text);
|
|
68
|
-
|
|
69
|
+
const vector = await embedder.embed(text);
|
|
70
|
+
|
|
71
|
+
// ✅ Defensive: skip invalid vectors
|
|
72
|
+
if (!Array.isArray(vector) || vector.length !== embedder.getDimension() || vector.every(v => v === 0)) {
|
|
73
|
+
console.warn(`⚠️ Skipping invalid vector for doc ${doc.id}:${i}`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
69
76
|
|
|
70
77
|
await vectorStore.upsert({
|
|
71
78
|
id: `${doc.id}:${i}`,
|
|
@@ -81,9 +88,15 @@ async function resolver(action, context = {}) {
|
|
|
81
88
|
}
|
|
82
89
|
|
|
83
90
|
// Embed query & search
|
|
84
|
-
const
|
|
91
|
+
const queryVector = await embedder.embed(query);
|
|
92
|
+
|
|
93
|
+
// ✅ Defensive: validate query vector
|
|
94
|
+
if (!Array.isArray(queryVector) || queryVector.length !== embedder.getDimension()) {
|
|
95
|
+
throw new Error("Query embedding invalid or not a proper array");
|
|
96
|
+
}
|
|
97
|
+
|
|
85
98
|
const results = await vectorStore.query({
|
|
86
|
-
vector,
|
|
99
|
+
vector: queryVector,
|
|
87
100
|
topK: context.topK || 5,
|
|
88
101
|
minScore: context.minScore || 0,
|
|
89
102
|
});
|