embedded-raptor 1.1.0 → 2.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.
Files changed (45) hide show
  1. package/README.md +11 -11
  2. package/dist/cli.cjs +26 -4
  3. package/dist/cli.mjs +25 -3
  4. package/dist/commands/delete.d.ts +41 -0
  5. package/dist/commands/delete.d.ts.map +1 -0
  6. package/dist/commands/index.d.ts +1 -0
  7. package/dist/commands/index.d.ts.map +1 -1
  8. package/dist/{engine-ez6nFONK.mjs → engine-BvJ0ls3b.mjs} +62 -30
  9. package/dist/engine-Cuz0P5Od.mjs +1164 -0
  10. package/dist/engine-DLM7PWhV.cjs +1203 -0
  11. package/dist/{engine-CTvg_66e.cjs → engine-Iq0_dbnk.cjs} +63 -31
  12. package/dist/engine.d.ts +55 -17
  13. package/dist/engine.d.ts.map +1 -1
  14. package/dist/index.cjs +1 -1
  15. package/dist/index.mjs +1 -1
  16. package/dist/storage-engine/constants.d.ts +53 -0
  17. package/dist/storage-engine/constants.d.ts.map +1 -0
  18. package/dist/storage-engine/data-format.d.ts +35 -0
  19. package/dist/storage-engine/data-format.d.ts.map +1 -0
  20. package/dist/storage-engine/file-lock.d.ts +35 -0
  21. package/dist/storage-engine/file-lock.d.ts.map +1 -0
  22. package/dist/storage-engine/index.d.ts +14 -0
  23. package/dist/storage-engine/index.d.ts.map +1 -0
  24. package/dist/storage-engine/key-index.d.ts +54 -0
  25. package/dist/storage-engine/key-index.d.ts.map +1 -0
  26. package/dist/storage-engine/migration.d.ts +26 -0
  27. package/dist/storage-engine/migration.d.ts.map +1 -0
  28. package/dist/storage-engine/mutex.d.ts +23 -0
  29. package/dist/storage-engine/mutex.d.ts.map +1 -0
  30. package/dist/storage-engine/storage-engine.d.ts +85 -0
  31. package/dist/storage-engine/storage-engine.d.ts.map +1 -0
  32. package/dist/storage-engine/types.d.ts +85 -0
  33. package/dist/storage-engine/types.d.ts.map +1 -0
  34. package/dist/storage-engine/wal-format.d.ts +22 -0
  35. package/dist/storage-engine/wal-format.d.ts.map +1 -0
  36. package/dist/storage-engine/wal.d.ts +32 -0
  37. package/dist/storage-engine/wal.d.ts.map +1 -0
  38. package/dist/types.d.ts +2 -0
  39. package/dist/types.d.ts.map +1 -1
  40. package/package.json +6 -2
  41. package/dist/engine-Bl1yeWoe.cjs +0 -374
  42. package/dist/engine-D06Gh_gw.mjs +0 -335
  43. package/dist/engine-DISO9uFr.mjs +0 -31601
  44. package/dist/engine-KhnrAv7v.cjs +0 -38642
  45. package/dist/engine-r-qHfsLd.cjs +0 -370
package/README.md CHANGED
@@ -9,16 +9,16 @@
9
9
  > A lightweight semantic search database with text embeddings for Node.js and
10
10
  > Bun
11
11
 
12
- Embedded Raptor lets you build semantic search into your applications with just a few
13
- lines of code. Store text, search by meaning, and find similar content—perfect
14
- for RAG systems, chatbots, and recommendation engines.
12
+ Embedded Raptor lets you build semantic search into your applications with just
13
+ a few lines of code. Store text, search by meaning, and find similar
14
+ content—perfect for RAG systems, chatbots, and recommendation engines.
15
15
 
16
16
  ## What is Embedded Raptor?
17
17
 
18
- Embedded Raptor is an embedding database that automatically converts text into vector
19
- embeddings and stores them in an efficient binary format. Instead of searching
20
- by exact keywords, you can search by semantic similarity—finding documents that
21
- mean the same thing, even if they use different words.
18
+ Embedded Raptor is an embedding database that automatically converts text into
19
+ vector embeddings and stores them in an efficient binary format. Instead of
20
+ searching by exact keywords, you can search by semantic similarity—finding
21
+ documents that mean the same thing, even if they use different words.
22
22
 
23
23
  **Example:** Search for "how to reset password" and find results like "forgot my
24
24
  login credentials" or "change account password".
@@ -203,12 +203,12 @@ raptor store key1 "Some text" --storePath ./data/custom.raptor
203
203
 
204
204
  ## How It Works
205
205
 
206
- 1. **Text → Embeddings**: Embedded Raptor uses the BGE-Base-EN model to convert text into
207
- 768-dimensional vector embeddings
206
+ 1. **Text → Embeddings**: Embedded Raptor uses the BGE-Base-EN model to convert
207
+ text into 768-dimensional vector embeddings
208
208
  2. **Storage**: Embeddings are stored in an efficient binary format (.raptor
209
209
  files)
210
- 3. **Search**: When you search, Embedded Raptor compares your query embedding against all
211
- stored embeddings using cosine similarity
210
+ 3. **Search**: When you search, Embedded Raptor compares your query embedding
211
+ against all stored embeddings using cosine similarity
212
212
  4. **Results**: Returns the most similar results ranked by similarity score
213
213
 
214
214
  **Embedding Model**:
package/dist/cli.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- const require_engine = require('./engine-CTvg_66e.cjs');
3
- let node_fs = require("node:fs");
4
- node_fs = require_engine.__toESM(node_fs);
2
+ const require_engine = require('./engine-DLM7PWhV.cjs');
5
3
  let node_path = require("node:path");
6
4
  node_path = require_engine.__toESM(node_path);
5
+ let node_fs = require("node:fs");
6
+ node_fs = require_engine.__toESM(node_fs);
7
7
  let cleye = require("cleye");
8
8
  cleye = require_engine.__toESM(cleye);
9
9
  let node_url = require("node:url");
@@ -89,6 +89,27 @@ const search = (0, cleye.command)({
89
89
  }
90
90
  });
91
91
 
92
+ //#endregion
93
+ //#region src/commands/delete.ts
94
+ const deleteCmd = (0, cleye.command)({
95
+ name: "delete",
96
+ description: "Delete an embedding entry by key",
97
+ parameters: ["<key>"],
98
+ flags: { ...sharedFlags }
99
+ }, async (argv) => {
100
+ const engine = new require_engine.EmbeddingEngine({ storePath: argv.flags.storePath });
101
+ try {
102
+ const [key] = argv._;
103
+ if (await engine.delete(key)) console.log(`Deleted key "${key}"`);
104
+ else {
105
+ console.log(`Key "${key}" not found`);
106
+ process.exit(1);
107
+ }
108
+ } finally {
109
+ await engine.dispose();
110
+ }
111
+ });
112
+
92
113
  //#endregion
93
114
  //#region src/cli.ts
94
115
  const __dirname$1 = (0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
@@ -100,7 +121,8 @@ function main() {
100
121
  commands: [
101
122
  store,
102
123
  get,
103
- search
124
+ search,
125
+ deleteCmd
104
126
  ]
105
127
  }, () => {});
106
128
  }
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { t as EmbeddingEngine } from "./engine-ez6nFONK.mjs";
3
- import { readFileSync } from "node:fs";
2
+ import { t as EmbeddingEngine } from "./engine-Cuz0P5Od.mjs";
4
3
  import { dirname, resolve } from "node:path";
4
+ import { readFileSync } from "node:fs";
5
5
  import { cli, command } from "cleye";
6
6
  import { fileURLToPath } from "node:url";
7
7
 
@@ -85,6 +85,27 @@ const search = command({
85
85
  }
86
86
  });
87
87
 
88
+ //#endregion
89
+ //#region src/commands/delete.ts
90
+ const deleteCmd = command({
91
+ name: "delete",
92
+ description: "Delete an embedding entry by key",
93
+ parameters: ["<key>"],
94
+ flags: { ...sharedFlags }
95
+ }, async (argv) => {
96
+ const engine = new EmbeddingEngine({ storePath: argv.flags.storePath });
97
+ try {
98
+ const [key] = argv._;
99
+ if (await engine.delete(key)) console.log(`Deleted key "${key}"`);
100
+ else {
101
+ console.log(`Key "${key}" not found`);
102
+ process.exit(1);
103
+ }
104
+ } finally {
105
+ await engine.dispose();
106
+ }
107
+ });
108
+
88
109
  //#endregion
89
110
  //#region src/cli.ts
90
111
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -96,7 +117,8 @@ function main() {
96
117
  commands: [
97
118
  store,
98
119
  get,
99
- search
120
+ search,
121
+ deleteCmd
100
122
  ]
101
123
  }, () => {});
102
124
  }
@@ -0,0 +1,41 @@
1
+ export declare const deleteCmd: import("cleye").Command<{
2
+ name: "delete";
3
+ description: string;
4
+ parameters: "<key>"[];
5
+ flags: {
6
+ storePath: {
7
+ readonly type: StringConstructor;
8
+ readonly description: "Path to the embeddings store file";
9
+ readonly default: "./database.raptor";
10
+ readonly alias: "s";
11
+ };
12
+ };
13
+ }, {
14
+ command: "delete";
15
+ } & import("type-flag").TypeFlag<{
16
+ storePath: {
17
+ readonly type: StringConstructor;
18
+ readonly description: "Path to the embeddings store file";
19
+ readonly default: "./database.raptor";
20
+ readonly alias: "s";
21
+ };
22
+ } & {
23
+ help: BooleanConstructor;
24
+ }> & {
25
+ _: {
26
+ key: string;
27
+ };
28
+ showHelp: (options?: {
29
+ version?: string;
30
+ description?: string;
31
+ usage?: false | string | string[];
32
+ examples?: string | string[];
33
+ render?: (nodes: {
34
+ id?: string;
35
+ type: keyof import("cleye").Renderers;
36
+ data: any;
37
+ }[], renderers: import("cleye").Renderers) => string;
38
+ }) => void;
39
+ showVersion: () => void;
40
+ }>;
41
+ //# sourceMappingURL=delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../src/commands/delete.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;sBA6B2kM,CAAC;;;;;;;;;;;;EADjmM,CAAA"}
@@ -1,4 +1,5 @@
1
1
  export { store } from './store';
2
2
  export { get } from './get';
3
3
  export { search } from './search';
4
+ export { deleteCmd } from './delete';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA"}
@@ -1,4 +1,4 @@
1
- import { env, pipeline } from "@xenova/transformers";
1
+ import { getLlama, resolveModelFile } from "node-llama-cpp";
2
2
  import { existsSync } from "node:fs";
3
3
  import { appendFile, mkdir, open, stat, writeFile } from "node:fs/promises";
4
4
  import { dirname } from "node:path";
@@ -221,35 +221,64 @@ var CandidateSetEntry = class {
221
221
 
222
222
  //#endregion
223
223
  //#region src/engine.ts
224
+ const DEFAULT_MODEL_URI = "hf:CompendiumLabs/bge-small-en-v1.5-gguf/bge-small-en-v1.5-q8_0.gguf";
225
+ const DEFAULT_CACHE_DIR = "./.cache/models";
224
226
  var EmbeddingEngine = class {
225
227
  fileReader;
226
228
  storePath;
227
- extractor;
229
+ cacheDir;
230
+ llama;
231
+ model;
232
+ embeddingContext;
233
+ initPromise;
228
234
  constructor(options) {
229
235
  this.storePath = options.storePath;
230
236
  this.fileReader = new BinaryFileReader(options.storePath);
231
- env.cacheDir = "./.cache";
237
+ this.cacheDir = options.cacheDir ?? DEFAULT_CACHE_DIR;
232
238
  }
233
239
  /**
234
240
  * Gets or initializes the embedding model
235
241
  * Caches the model instance to avoid repeated initialization overhead
236
- * @returns Initialized feature extraction pipeline
237
242
  */
238
- async getOrInitModel() {
239
- this.extractor ??= await pipeline("feature-extraction", "Xenova/bge-small-en-v1.5");
240
- return this.extractor;
243
+ async ensureModelLoaded() {
244
+ if (this.embeddingContext) return;
245
+ if (this.initPromise) return this.initPromise;
246
+ this.initPromise = this.initializeModel();
247
+ await this.initPromise;
248
+ }
249
+ async initializeModel() {
250
+ this.llama = await getLlama();
251
+ const modelPath = await resolveModelFile(DEFAULT_MODEL_URI, this.cacheDir);
252
+ this.model = await this.llama.loadModel({ modelPath });
253
+ this.embeddingContext = await this.model.createEmbeddingContext();
254
+ }
255
+ /**
256
+ * Truncates text to fit within the model's context size
257
+ * Uses the model's tokenizer for accurate token counting
258
+ * BGE-small supports 512 tokens, we use 500 to leave room for special tokens
259
+ */
260
+ truncateToContextSize(text) {
261
+ if (!this.model) {
262
+ const maxChars = 300 * 3;
263
+ return text.length <= maxChars ? text : text.slice(0, maxChars);
264
+ }
265
+ const maxTokens = 500;
266
+ const tokens = this.model.tokenize(text);
267
+ if (tokens.length <= maxTokens) return text;
268
+ const truncatedTokens = tokens.slice(0, maxTokens);
269
+ return this.model.detokenize(truncatedTokens);
241
270
  }
242
271
  /**
243
- * Generates embedding from text using Transformers.js bge-small-en-v1.5 model
272
+ * Generates embedding from text using node-llama-cpp with bge-small-en-v1.5 model
244
273
  * @param text - Text to embed
245
274
  * @returns 384-dimensional embedding vector (normalized)
246
275
  */
247
276
  async generateEmbedding(text) {
248
- const output = await (await this.getOrInitModel())(text, {
249
- pooling: "mean",
250
- normalize: true
251
- });
252
- return Array.from(output.data);
277
+ await this.ensureModelLoaded();
278
+ invariant(this.embeddingContext, "Embedding context not initialized");
279
+ const truncatedText = this.truncateToContextSize(text);
280
+ const embedding = await this.embeddingContext.getEmbeddingFor(truncatedText);
281
+ return Array.from(embedding.vector);
253
282
  }
254
283
  /**
255
284
  * Retrieves an embedding entry by key
@@ -303,26 +332,20 @@ var EmbeddingEngine = class {
303
332
  /**
304
333
  * Stores multiple text embeddings in batch
305
334
  * More efficient than calling store() multiple times
306
- * Generates embeddings in a single batch and writes all records at once
335
+ * Generates embeddings in parallel and writes all records at once
307
336
  * @param items - Array of {key, text} objects to store
308
337
  */
309
338
  async storeMany(items) {
310
339
  invariant(items.length > 0, "Items array must not be empty.");
311
- const texts = items.map((item) => item.text);
312
- const output = await (await this.getOrInitModel())(texts, {
313
- pooling: "mean",
314
- normalize: true
340
+ await this.ensureModelLoaded();
341
+ const embeddingContext = this.embeddingContext;
342
+ invariant(embeddingContext, "Embedding context not initialized");
343
+ const embeddingPromises = items.map(async (item) => {
344
+ const truncatedText = this.truncateToContextSize(item.text);
345
+ const embedding = await embeddingContext.getEmbeddingFor(truncatedText);
346
+ return Array.from(embedding.vector);
315
347
  });
316
- const batchSize = output.dims[0];
317
- const embeddingDim = output.dims[1];
318
- const embeddingsList = [];
319
- for (let i = 0; i < batchSize; i++) {
320
- const start = i * embeddingDim;
321
- const end = start + embeddingDim;
322
- const data = Array.from(output.data);
323
- embeddingsList.push(data.slice(start, end));
324
- }
325
- invariant(embeddingsList.length === items.length, "Number of embeddings must match number of items.");
348
+ const embeddingsList = await Promise.all(embeddingPromises);
326
349
  await mkdir(dirname(this.storePath), { recursive: true });
327
350
  if (!existsSync(this.storePath)) await writeHeader(this.storePath, embeddingsList[0].length);
328
351
  const records = items.map((item, index) => ({
@@ -356,8 +379,17 @@ var EmbeddingEngine = class {
356
379
  * Disposes of the cached embedding model and releases resources
357
380
  * Call this when you're done using the engine to free up memory
358
381
  */
359
- dispose() {
360
- this.extractor = void 0;
382
+ async dispose() {
383
+ if (this.embeddingContext) {
384
+ await this.embeddingContext.dispose();
385
+ this.embeddingContext = void 0;
386
+ }
387
+ if (this.model) {
388
+ await this.model.dispose();
389
+ this.model = void 0;
390
+ }
391
+ this.llama = void 0;
392
+ this.initPromise = void 0;
361
393
  }
362
394
  };
363
395