@wrongstack/vector-memory 0.320.1 → 1.0.0
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/dist/index.js +13 -8
- package/dist/sage-fusion.d.ts +18 -3
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -249,6 +249,11 @@ function encodeVector(vec) {
|
|
|
249
249
|
return Buffer.from(vec.buffer, vec.byteOffset, vec.byteLength);
|
|
250
250
|
}
|
|
251
251
|
function decodeVector(buf) {
|
|
252
|
+
if (buf.byteLength % 4 !== 0) {
|
|
253
|
+
throw new Error(
|
|
254
|
+
`decodeVector: invalid vector byteLength ${buf.byteLength} (must be a multiple of 4)`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
252
257
|
const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
253
258
|
const copy = new Float32Array(buf.byteLength / 4);
|
|
254
259
|
for (let i = 0; i < copy.length; i++) {
|
|
@@ -264,6 +269,12 @@ import * as path from "node:path";
|
|
|
264
269
|
import { withFileLock } from "@wrongstack/core/utils";
|
|
265
270
|
import { loadRuntimeDatabaseSync } from "@wrongstack/persistence";
|
|
266
271
|
import { cosineSimilarity, HashingEmbeddingProvider } from "@wrongstack/sage";
|
|
272
|
+
var DEFAULT_SEARCH_LIMIT = 10;
|
|
273
|
+
function normalizeLimit(limit) {
|
|
274
|
+
if (limit === void 0 || !Number.isFinite(limit)) return DEFAULT_SEARCH_LIMIT;
|
|
275
|
+
const floored = Math.floor(limit);
|
|
276
|
+
return floored < 1 ? DEFAULT_SEARCH_LIMIT : floored;
|
|
277
|
+
}
|
|
267
278
|
var DEFAULT_DIRECTORY = ".wrongstack/vector-memory";
|
|
268
279
|
var DEFAULT_FILENAME = "vector-memory.db";
|
|
269
280
|
var DEFAULT_LOCK_TIMEOUT_MS = 5e3;
|
|
@@ -525,7 +536,7 @@ var VectorMemoryStore = class _VectorMemoryStore {
|
|
|
525
536
|
}
|
|
526
537
|
async search(query, opts = {}) {
|
|
527
538
|
this.assertOpen();
|
|
528
|
-
const limit = opts.limit
|
|
539
|
+
const limit = normalizeLimit(opts.limit);
|
|
529
540
|
const threshold = opts.threshold ?? 0;
|
|
530
541
|
const includeVectors = opts.includeVectors === true;
|
|
531
542
|
if (typeof query !== "string" || query.trim().length === 0) return [];
|
|
@@ -1214,12 +1225,6 @@ async function fuseWithVectorMemory(query, lexical, options = {}) {
|
|
|
1214
1225
|
}
|
|
1215
1226
|
const sageById = /* @__PURE__ */ new Map();
|
|
1216
1227
|
for (const memory of lexical) sageById.set(memory.id, memory);
|
|
1217
|
-
for (const hit of vectorHits) {
|
|
1218
|
-
const sageId = hit.entry.metadata?.["sageId"];
|
|
1219
|
-
if (typeof sageId === "string" && !sageById.has(sageId)) {
|
|
1220
|
-
continue;
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
1228
|
const lexicalRanked = lexical.map((memory, index) => ({
|
|
1224
1229
|
memory,
|
|
1225
1230
|
rankScore: lexicalRankScore(index, lexical.length),
|
|
@@ -1237,7 +1242,7 @@ async function fuseWithVectorMemory(query, lexical, options = {}) {
|
|
|
1237
1242
|
const fused = /* @__PURE__ */ new Map();
|
|
1238
1243
|
for (let i = 0; i < lexicalRanked.length; i++) {
|
|
1239
1244
|
const c = lexicalRanked[i];
|
|
1240
|
-
const rrf =
|
|
1245
|
+
const rrf = (1 - weight) * (1 / (k + i + 1));
|
|
1241
1246
|
fused.set(c.memory.id, {
|
|
1242
1247
|
memory: c.memory,
|
|
1243
1248
|
vectorScore: null,
|
package/dist/sage-fusion.d.ts
CHANGED
|
@@ -6,8 +6,15 @@
|
|
|
6
6
|
*
|
|
7
7
|
* The fusion is a Reciprocal Rank Fusion (RRF)-style blend rather than a
|
|
8
8
|
* raw cosine-blend, so it stays robust when one side returns nothing
|
|
9
|
-
* (e.g. embedding provider unavailable).
|
|
10
|
-
*
|
|
9
|
+
* (e.g. embedding provider unavailable).
|
|
10
|
+
*
|
|
11
|
+
* IMPORTANT — the vector channel can only RE-RANK the lexical list, never
|
|
12
|
+
* extend it. A vector hit is kept only when its `metadata.sageId` resolves to
|
|
13
|
+
* a memory already present in `lexical`, because the caller's lexical list is
|
|
14
|
+
* the authoritative source of `Sage` objects and this function will not
|
|
15
|
+
* fabricate one (pinned by tests/sage-fusion.test.ts). Therefore:
|
|
16
|
+
* - `lexical` may be `[]` → the result is `[]`, whatever the vector channel
|
|
17
|
+
* found. This is NOT a fallback to pure vector ranking.
|
|
11
18
|
* - `vector` may be `[]` → fusion falls back to pure lexical ranking.
|
|
12
19
|
* - either may be `undefined` → fusion silently drops that channel.
|
|
13
20
|
*
|
|
@@ -40,6 +47,10 @@ export interface SageFusionOptions {
|
|
|
40
47
|
/**
|
|
41
48
|
* Cosine threshold below which a vector-only hit is dropped (no lexical
|
|
42
49
|
* counterpart to lift it). Default 0 — keep all, let RRF decide.
|
|
50
|
+
*
|
|
51
|
+
* Currently inert: vector-only hits cannot occur (see the module docstring),
|
|
52
|
+
* so nothing ever reaches this threshold. Kept for API stability and for
|
|
53
|
+
* the day the vector channel is allowed to extend the candidate set.
|
|
43
54
|
*/
|
|
44
55
|
vectorOnlyThreshold?: number | undefined;
|
|
45
56
|
}
|
|
@@ -51,7 +62,11 @@ export interface SageFusionHit {
|
|
|
51
62
|
lexicalScore: number | null;
|
|
52
63
|
/** 0..1, monotonically higher = better. */
|
|
53
64
|
finalScore: number;
|
|
54
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* Where the candidate came from. `'vector'` is currently unreachable —
|
|
67
|
+
* every candidate originates in the lexical list (see the module
|
|
68
|
+
* docstring); the vector channel only upgrades one to `'both'`.
|
|
69
|
+
*/
|
|
55
70
|
source: 'lexical' | 'vector' | 'both';
|
|
56
71
|
}
|
|
57
72
|
declare function lexicalRankScore(index: number, total: number): number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/vector-memory",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack Vector Memory — an additional vector-search memory store powered by @huggingface/transformers (local ONNX embeddings), alongside the SAGE lexical memory system.",
|
|
6
6
|
"repository": {
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"README.md"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@wrongstack/core": "0.
|
|
31
|
-
"@wrongstack/persistence": "0.
|
|
32
|
-
"@wrongstack/sage": "0.
|
|
30
|
+
"@wrongstack/core": "1.0.0",
|
|
31
|
+
"@wrongstack/persistence": "1.0.0",
|
|
32
|
+
"@wrongstack/sage": "1.0.0"
|
|
33
33
|
},
|
|
34
34
|
"optionalDependencies": {
|
|
35
35
|
"@huggingface/transformers": "^4.2.0"
|