@wrongstack/vector-memory 1.0.8 → 1.0.10

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 CHANGED
@@ -378,8 +378,13 @@ function createSageSurfaceSyncSource(sage, opts = {}) {
378
378
  const requested = limit === void 0 ? maxTotal : clamp(limit, 1, maxTotal === Number.POSITIVE_INFINITY ? limit : maxTotal);
379
379
  const memories = [];
380
380
  let cursor;
381
+ const seenCursors = /* @__PURE__ */ new Set();
381
382
  let noProgressPages = 0;
382
383
  while (memories.length < requested) {
384
+ if (cursor !== void 0) {
385
+ if (seenCursors.has(cursor)) break;
386
+ seenCursors.add(cursor);
387
+ }
383
388
  const remaining = requested - memories.length;
384
389
  const page = await sage.listSagePage({
385
390
  statuses: ["active"],
@@ -402,6 +407,7 @@ function createSageSurfaceSyncSource(sage, opts = {}) {
402
407
  });
403
408
  }
404
409
  if (!page.nextCursor) break;
410
+ if (seenCursors.has(page.nextCursor)) break;
405
411
  if (rows.length === 0) {
406
412
  noProgressPages++;
407
413
  if (noProgressPages > 3) break;
@@ -929,9 +935,9 @@ var VectorMemoryStore = class _VectorMemoryStore {
929
935
  * Embed `text`, hitting the provider-level cache first. Cache miss falls
930
936
  * through to the configured provider and writes the result back. Returns
931
937
  * `undefined` when the provider fails — the caller can persist the entry
932
- * without a vector (fail-open).
938
+ * without a vector (fail-open) — unless `strict`, which throws instead.
933
939
  */
934
- async embedWithCache(text) {
940
+ async embedWithCache(text, strict = false) {
935
941
  const now = (/* @__PURE__ */ new Date()).toISOString();
936
942
  const cached = this.cachedVector(text, now);
937
943
  if (cached) return cached;
@@ -940,7 +946,13 @@ var VectorMemoryStore = class _VectorMemoryStore {
940
946
  const vec = result[0];
941
947
  if (vec) this.cacheVector(text, vec, now);
942
948
  return vec;
943
- } catch {
949
+ } catch (err) {
950
+ if (strict) {
951
+ throw new VectorMemoryProviderUnavailableError(
952
+ `Embedding provider "${this.provider.id}" failed: ${err instanceof Error ? err.message : String(err)}`,
953
+ err
954
+ );
955
+ }
944
956
  return void 0;
945
957
  }
946
958
  }
@@ -1097,8 +1109,16 @@ var VectorMemoryStore = class _VectorMemoryStore {
1097
1109
  const threshold = opts.threshold ?? 0;
1098
1110
  const includeVectors = opts.includeVectors === true;
1099
1111
  if (typeof query !== "string" || query.trim().length === 0) return [];
1100
- const queryVec = await this.embedWithCache(query);
1101
- if (!queryVec || queryVec.length === 0) return [];
1112
+ const strict = opts.failOnEmbeddingError === true;
1113
+ const queryVec = await this.embedWithCache(query, strict);
1114
+ if (!queryVec || queryVec.length === 0) {
1115
+ if (strict) {
1116
+ throw new VectorMemoryProviderUnavailableError(
1117
+ `Embedding provider "${this.provider.id}" returned no vector for the query.`
1118
+ );
1119
+ }
1120
+ return [];
1121
+ }
1102
1122
  const providerId = this.provider.id;
1103
1123
  const dimensions = this.provider.dimensions;
1104
1124
  const filters = ["v.provider_id = ?", "v.dimensions = ?"];
@@ -1421,7 +1441,7 @@ function vectorMemorySearchTool(store) {
1421
1441
  return {
1422
1442
  name: "vector_memory_search",
1423
1443
  category: "Memory",
1424
- description: "Semantic search over the vector memory store. Embeds the query with the active provider and returns the top-k entries ranked by cosine similarity. Returns an empty list when the embedding provider is unavailable \u2014 callers should fall back to lexical search.",
1444
+ description: "Semantic search over the vector memory store. Embeds the query with the active provider and returns the top-k entries ranked by cosine similarity. Fails when the embedding provider is unavailable \u2014 fall back to lexical search (sage `memory_search`) in that case.",
1425
1445
  usageHint: "Use when you want results ranked by meaning. Pairs well with sage `memory_search` for keyword precision.",
1426
1446
  permission: "auto",
1427
1447
  mutating: false,
@@ -1464,7 +1484,9 @@ function vectorMemorySearchTool(store) {
1464
1484
  limit: input.limit !== void 0 ? input.limit : void 0,
1465
1485
  threshold: input.threshold !== void 0 ? input.threshold : void 0,
1466
1486
  scope: input.scope,
1467
- kind: input.kind
1487
+ kind: input.kind,
1488
+ // An embedding outage must fail the call, not look like "no matches".
1489
+ failOnEmbeddingError: true
1468
1490
  });
1469
1491
  return {
1470
1492
  hits: hits.map((h) => ({
@@ -1522,7 +1544,12 @@ function vectorMemoryForgetTool(store) {
1522
1544
  required: ["id"],
1523
1545
  additionalProperties: false
1524
1546
  },
1525
- execute: async (input) => ({ removed: await store.forget(input.id) })
1547
+ execute: async (input) => {
1548
+ if (!await store.forget(input.id)) {
1549
+ throw new Error(`vector_memory_forget: no entry with id "${input.id}".`);
1550
+ }
1551
+ return { removed: true };
1552
+ }
1526
1553
  };
1527
1554
  }
1528
1555
 
@@ -1547,7 +1574,8 @@ var TransformersEmbeddingProvider = class {
1547
1574
  this.cacheDir = opts.cacheDir;
1548
1575
  this.dtype = opts.dtype ?? DEFAULT_VECTOR_DTYPE;
1549
1576
  this.device = opts.device ?? "cpu";
1550
- this.batchSize = opts.batchSize ?? 16;
1577
+ const batchSize = opts.batchSize ?? 16;
1578
+ this.batchSize = Number.isFinite(batchSize) && batchSize >= 1 ? Math.floor(batchSize) : 16;
1551
1579
  this.maxChars = opts.maxChars ?? 2048;
1552
1580
  this.allowRemote = opts.allowRemoteModels ?? true;
1553
1581
  this.dimensions = DEFAULT_VECTOR_DIMENSIONS;
@@ -1595,7 +1623,15 @@ var TransformersEmbeddingProvider = class {
1595
1623
  if (Array.isArray(nested) && Array.isArray(nested[0])) {
1596
1624
  return nested.map((row) => Float32Array.from(row));
1597
1625
  }
1598
- return [Float32Array.from(nested)];
1626
+ const flat2 = nested;
1627
+ if (batchSize > 1 && flat2.length > 0 && flat2.length % batchSize === 0) {
1628
+ const dimensions = flat2.length / batchSize;
1629
+ return Array.from(
1630
+ { length: batchSize },
1631
+ (_, index) => Float32Array.from(flat2.slice(index * dimensions, (index + 1) * dimensions))
1632
+ );
1633
+ }
1634
+ return [Float32Array.from(flat2)];
1599
1635
  }
1600
1636
  const flat = out.data;
1601
1637
  if (flat instanceof Float32Array) {
package/dist/store.d.ts CHANGED
@@ -37,7 +37,7 @@ export declare class VectorMemoryStore {
37
37
  * Embed `text`, hitting the provider-level cache first. Cache miss falls
38
38
  * through to the configured provider and writes the result back. Returns
39
39
  * `undefined` when the provider fails — the caller can persist the entry
40
- * without a vector (fail-open).
40
+ * without a vector (fail-open) — unless `strict`, which throws instead.
41
41
  */
42
42
  private embedWithCache;
43
43
  /**
package/dist/types.d.ts CHANGED
@@ -55,6 +55,13 @@ export interface VectorSearchOptions {
55
55
  * build the pairwise-similarity heatmap.
56
56
  */
57
57
  includeVectors?: boolean | undefined;
58
+ /**
59
+ * When true, a failed query embedding THROWS
60
+ * `VectorMemoryProviderUnavailableError` instead of returning `[]`. The
61
+ * default (fail-open) suits fusion callers; the agent tool sets it so an
62
+ * outage is not reported as "no matches".
63
+ */
64
+ failOnEmbeddingError?: boolean | undefined;
58
65
  }
59
66
  export interface VectorSearchHit {
60
67
  entry: VectorEntry;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/vector-memory",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
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,14 +27,14 @@
27
27
  "README.md"
28
28
  ],
29
29
  "dependencies": {
30
- "@wrongstack/core": "1.0.8",
31
- "@wrongstack/persistence": "1.0.8",
32
- "@wrongstack/sage": "1.0.8"
30
+ "@wrongstack/core": "1.0.10",
31
+ "@wrongstack/persistence": "1.0.10",
32
+ "@wrongstack/sage": "1.0.10"
33
33
  },
34
34
  "devDependencies": {
35
- "@types/node": "^26.2.0",
35
+ "@types/node": "^26.5.1",
36
36
  "typescript": "^7.0.2",
37
- "vitest": "^4.1.11"
37
+ "vitest": "^5.0.0"
38
38
  },
39
39
  "publishConfig": {
40
40
  "access": "public",