@yamo/memory-mesh 3.2.4 → 3.2.5

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.
@@ -85,6 +85,11 @@ export declare class LanceDBClient {
85
85
  * @throws {QueryError} If stats query fails
86
86
  */
87
87
  getStats(): Promise<any>;
88
+ /**
89
+ * Compact old data files and prune versions older than 7 days.
90
+ * Best-effort — never throws.
91
+ */
92
+ optimize(): Promise<void>;
88
93
  /**
89
94
  * Sanitize an ID to prevent SQL injection
90
95
  * Removes any characters that aren't alphanumeric, underscore, or hyphen
@@ -201,7 +201,7 @@ export class LanceDBClient {
201
201
  await this.connect();
202
202
  }
203
203
  this._validateVector(vector);
204
- const { limit = 10, nprobes = 20, filter = null } = options;
204
+ const { limit = 10, nprobes = 20, filter = null, refineFactor, timeoutMs } = options;
205
205
  return this._retryOperation(async () => {
206
206
  if (!this.table) {
207
207
  throw new StorageError("Table not initialized");
@@ -217,12 +217,21 @@ export class LanceDBClient {
217
217
  // ignore
218
218
  }
219
219
  }
220
+ // Apply refineFactor for improved ANN recall (fetches N×candidates, reranks)
221
+ if (refineFactor && typeof refineFactor === "number") {
222
+ try {
223
+ query = query.refineFactor(refineFactor);
224
+ }
225
+ catch (_e) {
226
+ // ignore if not supported
227
+ }
228
+ }
220
229
  // Apply filter if provided
221
230
  if (filter) {
222
231
  query = query.where(filter);
223
232
  }
224
- // Execute search with limit
225
- const resultsArray = await query.limit(limit).toArray();
233
+ // Execute search with limit (and optional timeout)
234
+ const resultsArray = await query.limit(limit).toArray(timeoutMs ? { timeoutMs } : undefined);
226
235
  return resultsArray.map((row) => ({
227
236
  id: row.id,
228
237
  content: row.content,
@@ -385,6 +394,22 @@ export class LanceDBClient {
385
394
  };
386
395
  });
387
396
  }
397
+ /**
398
+ * Compact old data files and prune versions older than 7 days.
399
+ * Best-effort — never throws.
400
+ */
401
+ async optimize() {
402
+ if (!this.isConnected || !this.table)
403
+ return;
404
+ try {
405
+ await this.table.optimize({
406
+ cleanupOlderThan: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
407
+ });
408
+ }
409
+ catch (_e) {
410
+ // Best-effort — never block normal operations
411
+ }
412
+ }
388
413
  /**
389
414
  * Sanitize an ID to prevent SQL injection
390
415
  * Removes any characters that aren't alphanumeric, underscore, or hyphen
@@ -201,7 +201,7 @@ export class LanceDBClient {
201
201
  await this.connect();
202
202
  }
203
203
  this._validateVector(vector);
204
- const { limit = 10, nprobes = 20, filter = null } = options;
204
+ const { limit = 10, nprobes = 20, filter = null, refineFactor, timeoutMs } = options;
205
205
  return this._retryOperation(async () => {
206
206
  if (!this.table) {
207
207
  throw new StorageError("Table not initialized");
@@ -217,12 +217,23 @@ export class LanceDBClient {
217
217
  // ignore
218
218
  }
219
219
  }
220
+ // Apply refineFactor for improved ANN recall (fetches N×candidates, reranks)
221
+ if (refineFactor && typeof refineFactor === "number") {
222
+ try {
223
+ query = query.refineFactor(refineFactor);
224
+ }
225
+ catch (_e) {
226
+ // ignore if not supported
227
+ }
228
+ }
220
229
  // Apply filter if provided
221
230
  if (filter) {
222
231
  query = query.where(filter);
223
232
  }
224
- // Execute search with limit
225
- const resultsArray = await query.limit(limit).toArray();
233
+ // Execute search with limit (and optional timeout)
234
+ const resultsArray = await query.limit(limit).toArray(
235
+ timeoutMs ? { timeoutMs } : undefined,
236
+ );
226
237
  return resultsArray.map((row) => ({
227
238
  id: row.id,
228
239
  content: row.content,
@@ -385,6 +396,21 @@ export class LanceDBClient {
385
396
  };
386
397
  });
387
398
  }
399
+ /**
400
+ * Compact old data files and prune versions older than 7 days.
401
+ * Best-effort — never throws.
402
+ */
403
+ async optimize() {
404
+ if (!this.isConnected || !this.table) return;
405
+ try {
406
+ await this.table.optimize({
407
+ cleanupOlderThan: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
408
+ });
409
+ }
410
+ catch (_e) {
411
+ // Best-effort — never block normal operations
412
+ }
413
+ }
388
414
  /**
389
415
  * Sanitize an ID to prevent SQL injection
390
416
  * Removes any characters that aren't alphanumeric, underscore, or hyphen
@@ -444,6 +444,11 @@ export declare class MemoryMesh {
444
444
  * await mesh.close(); // Clean up
445
445
  * ```
446
446
  */
447
+ /**
448
+ * Compact old data files and prune versions older than 7 days.
449
+ * Best-effort — delegates to LanceDBClient.optimize().
450
+ */
451
+ optimize(): Promise<any>;
447
452
  close(): Promise<void>;
448
453
  }
449
454
  /**
@@ -1714,6 +1714,13 @@ description: Auto-generated skill to handle: ${enrichedPrompt || topic}
1714
1714
  * await mesh.close(); // Clean up
1715
1715
  * ```
1716
1716
  */
1717
+ /**
1718
+ * Compact old data files and prune versions older than 7 days.
1719
+ * Best-effort — delegates to LanceDBClient.optimize().
1720
+ */
1721
+ async optimize() {
1722
+ return this.client?.optimize?.();
1723
+ }
1717
1724
  // eslint-disable-next-line @typescript-eslint/require-await
1718
1725
  async close() {
1719
1726
  try {
@@ -1801,6 +1801,13 @@ description: Auto-generated skill to handle: ${enrichedPrompt || topic}
1801
1801
  * await mesh.close(); // Clean up
1802
1802
  * ```
1803
1803
  */
1804
+ /**
1805
+ * Compact old data files and prune versions older than 7 days.
1806
+ * Best-effort — delegates to LanceDBClient.optimize().
1807
+ */
1808
+ async optimize() {
1809
+ return this.client?.optimize?.();
1810
+ }
1804
1811
  // eslint-disable-next-line @typescript-eslint/require-await
1805
1812
  async close() {
1806
1813
  try {
@@ -65,6 +65,12 @@ export declare function isSchemaV2(schema: any): any;
65
65
  * Safe to call on any table — non-memory tables skip the schema column additions.
66
66
  */
67
67
  export declare function migrateTableV2(table: any): Promise<void>;
68
+ /**
69
+ * Ensure the vector column has an IVF_PQ index.
70
+ * Skipped when: table has too few rows, index already exists, or table is a mock.
71
+ * Called automatically by createMemoryTableWithDimension after migration.
72
+ */
73
+ export declare function ensureVectorIndex(table: any): Promise<void>;
68
74
  /**
69
75
  * Memory table schema using Apache Arrow format (default 384 dimensions)
70
76
  * @deprecated Use createMemorySchema(vectorDim) for dynamic dimensions
@@ -122,6 +128,7 @@ declare const _default: {
122
128
  createMemorySchemaV2: typeof createMemorySchemaV2;
123
129
  isSchemaV2: typeof isSchemaV2;
124
130
  migrateTableV2: typeof migrateTableV2;
131
+ ensureVectorIndex: typeof ensureVectorIndex;
125
132
  getEmbeddingDimension: typeof getEmbeddingDimension;
126
133
  DEFAULT_VECTOR_DIMENSION: number;
127
134
  EMBEDDING_DIMENSIONS: {
@@ -9,6 +9,7 @@
9
9
  * - text-embedding-3-small: 1536 dimensions
10
10
  */
11
11
  import * as arrow from "apache-arrow";
12
+ import { Index } from "@lancedb/lancedb";
12
13
  /**
13
14
  * Default vector dimension (all-MiniLM-L6-v2)
14
15
  */
@@ -153,6 +154,34 @@ export async function migrateTableV2(table) {
153
154
  { name: "last_accessed", valueSql: "cast(null as timestamp)" },
154
155
  ]);
155
156
  }
157
+ /**
158
+ * Ensure the vector column has an IVF_PQ index.
159
+ * Skipped when: table has too few rows, index already exists, or table is a mock.
160
+ * Called automatically by createMemoryTableWithDimension after migration.
161
+ */
162
+ export async function ensureVectorIndex(table) {
163
+ if (typeof table.listIndices !== "function")
164
+ return;
165
+ try {
166
+ const indices = await table.listIndices();
167
+ if (indices.some((i) => i.columns.includes("vector")))
168
+ return;
169
+ const rowCount = await table.countRows();
170
+ if (rowCount < INDEX_CONFIG.vector.num_partitions)
171
+ return;
172
+ await table.createIndex("vector", {
173
+ config: Index.ivfPq({
174
+ numPartitions: INDEX_CONFIG.vector.num_partitions,
175
+ numSubVectors: INDEX_CONFIG.vector.num_sub_vectors,
176
+ distanceType: INDEX_CONFIG.vector.metric,
177
+ }),
178
+ replace: false,
179
+ });
180
+ }
181
+ catch {
182
+ // Index creation is best-effort — never block table access
183
+ }
184
+ }
156
185
  /**
157
186
  * Memory table schema using Apache Arrow format (default 384 dimensions)
158
187
  * @deprecated Use createMemorySchema(vectorDim) for dynamic dimensions
@@ -209,6 +238,8 @@ export async function createMemoryTableWithDimension(db, tableName, vectorDim) {
209
238
  }
210
239
  // Migrate existing tables to V2 (manifest paths + schema columns, idempotent)
211
240
  await migrateTableV2(table);
241
+ // Ensure vector index exists (no-op if already present or insufficient rows)
242
+ await ensureVectorIndex(table);
212
243
  return table;
213
244
  }
214
245
  catch (error) {
@@ -225,6 +256,7 @@ export default {
225
256
  createMemorySchemaV2,
226
257
  isSchemaV2,
227
258
  migrateTableV2,
259
+ ensureVectorIndex,
228
260
  getEmbeddingDimension,
229
261
  DEFAULT_VECTOR_DIMENSION,
230
262
  EMBEDDING_DIMENSIONS,
@@ -9,6 +9,8 @@
9
9
  * - text-embedding-3-small: 1536 dimensions
10
10
  */
11
11
  import * as arrow from "apache-arrow";
12
+ import * as lancedb from "@lancedb/lancedb";
13
+ import { Index } from "@lancedb/lancedb";
12
14
  /**
13
15
  * Default vector dimension (all-MiniLM-L6-v2)
14
16
  */
@@ -150,6 +152,31 @@ export async function migrateTableV2(table) {
150
152
  { name: "last_accessed", valueSql: "cast(null as timestamp)" },
151
153
  ]);
152
154
  }
155
+ /**
156
+ * Ensure the vector column has an IVF_PQ index.
157
+ * Skipped when: table has too few rows, index already exists, or table is a mock.
158
+ * Called automatically by createMemoryTableWithDimension after migration.
159
+ */
160
+ export async function ensureVectorIndex(table) {
161
+ if (typeof table.listIndices !== "function") return;
162
+ try {
163
+ const indices = await table.listIndices();
164
+ if (indices.some((i) => i.columns.includes("vector"))) return;
165
+ const rowCount = await table.countRows();
166
+ if (rowCount < INDEX_CONFIG.vector.num_partitions) return;
167
+ await table.createIndex("vector", {
168
+ config: Index.ivfPq({
169
+ numPartitions: INDEX_CONFIG.vector.num_partitions,
170
+ numSubVectors: INDEX_CONFIG.vector.num_sub_vectors,
171
+ distanceType: INDEX_CONFIG.vector.metric,
172
+ }),
173
+ replace: false,
174
+ });
175
+ }
176
+ catch {
177
+ // Index creation is best-effort — never block table access
178
+ }
179
+ }
153
180
  /**
154
181
  * Memory table schema using Apache Arrow format (default 384 dimensions)
155
182
  * @deprecated Use createMemorySchema(vectorDim) for dynamic dimensions
@@ -206,6 +233,8 @@ export async function createMemoryTableWithDimension(db, tableName, vectorDim) {
206
233
  }
207
234
  // Migrate existing tables to V2 (manifest paths + schema columns, idempotent)
208
235
  await migrateTableV2(table);
236
+ // Ensure vector index exists (no-op if already present or insufficient rows)
237
+ await ensureVectorIndex(table);
209
238
  return table;
210
239
  }
211
240
  catch (error) {
@@ -222,6 +251,7 @@ export default {
222
251
  createMemorySchemaV2,
223
252
  isSchemaV2,
224
253
  migrateTableV2,
254
+ ensureVectorIndex,
225
255
  getEmbeddingDimension,
226
256
  DEFAULT_VECTOR_DIMENSION,
227
257
  EMBEDDING_DIMENSIONS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yamo/memory-mesh",
3
- "version": "3.2.4",
3
+ "version": "3.2.5",
4
4
  "description": "Portable semantic memory system with Layer 0 Scrubber for YAMO agents (v3 Singularity Edition)",
5
5
  "repository": {
6
6
  "type": "git",