@memvid/sdk 2.0.140 → 2.0.143

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 (3) hide show
  1. package/README.md +222 -277
  2. package/dist/index.js +27 -6
  3. package/package.json +5 -5
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @memvid/sdk
2
2
 
3
- Single-file AI memory system for Node.js. Store documents, search with BM25 ranking, and run retrieval-augmented generation (RAG) queries from a portable `.mv2` file.
3
+ A single-file AI memory system for Node.js. Store documents, search with BM25 + vector ranking, and run RAG queries from a portable `.mv2` file.
4
4
 
5
- Built on Rust via N-API for native performance. No database setup, no network dependencies, no configuration files.
5
+ Built on Rust via N-API. No database setup, no external services required.
6
6
 
7
7
  ## Install
8
8
 
@@ -10,392 +10,337 @@ Built on Rust via N-API for native performance. No database setup, no network de
10
10
  npm install @memvid/sdk
11
11
  ```
12
12
 
13
- ## Quick start
13
+ The package automatically installs the correct binary for your platform (macOS, Linux, or Windows).
14
14
 
15
- ```typescript
16
- import { use, create } from "@memvid/sdk";
15
+ ## Quick Start
17
16
 
18
- // Create a new memory file
19
- const mv = await use("basic", "notes.mv2", { mode: "auto" });
17
+ ```javascript
18
+ import { create } from "@memvid/sdk";
19
+
20
+ // Create a memory file
21
+ const mv = await create("notes.mv2");
20
22
 
21
- // Store a document
23
+ // Store some documents
22
24
  await mv.put({
23
- title: "Project kickoff",
25
+ title: "Project Update",
24
26
  label: "meeting",
25
- text: "Discussed timeline, assigned tasks to team members.",
26
- metadata: { date: "2024-01-15" },
27
+ text: "Discussed Q4 roadmap. Alice will handle the frontend refactor.",
28
+ metadata: { date: "2024-01-15", attendees: ["Alice", "Bob"] }
29
+ });
30
+
31
+ await mv.put({
32
+ title: "Technical Decision",
33
+ label: "architecture",
34
+ text: "Decided to use PostgreSQL for the main database. Redis for caching.",
27
35
  });
28
36
 
29
37
  // Search by keyword
30
- const results = await mv.find("timeline");
38
+ const results = await mv.find("database");
31
39
  console.log(results.hits);
32
40
 
33
- // Ask a question (retrieves relevant context)
34
- const answer = await mv.ask("What was discussed in the kickoff?");
35
- console.log(answer.context);
41
+ // Ask a question
42
+ const answer = await mv.ask("What database are we using?", {
43
+ model: "openai:gpt-4o-mini"
44
+ });
45
+ console.log(answer.text);
36
46
 
37
- // Commit and close
47
+ // Close the file
38
48
  await mv.seal();
39
49
  ```
40
50
 
41
51
  ## Core API
42
52
 
43
- ### Opening a memory
53
+ ### Opening and Creating
54
+
55
+ ```javascript
56
+ import { create, use } from "@memvid/sdk";
57
+
58
+ // Create a new memory file
59
+ const mv = await create("notes.mv2");
60
+
61
+ // Open an existing file
62
+ const mv = await use("basic", "notes.mv2", { mode: "open" });
44
63
 
45
- ```typescript
46
- const mv = await use(kind, path, options?)
64
+ // Create or open (auto mode)
65
+ const mv = await use("basic", "notes.mv2", { mode: "auto" });
66
+
67
+ // Open read-only
68
+ const mv = await use("basic", "notes.mv2", { readOnly: true });
47
69
  ```
48
70
 
49
- | Parameter | Type | Description |
50
- |-----------|------|-------------|
51
- | `kind` | `string` | Adapter type: `"basic"`, `"langchain"`, `"llamaindex"`, `"openai"`, `"crewai"`, `"vercel-ai"`, `"autogen"` |
52
- | `path` | `string` | Path to `.mv2` file |
53
- | `options.mode` | `string` | `"open"` (default), `"create"`, or `"auto"` |
54
- | `options.enableLex` | `boolean` | Enable lexical index (default: `true`) |
55
- | `options.enableVec` | `boolean` | Enable vector index (default: `true`) |
56
- | `options.readOnly` | `boolean` | Open in read-only mode (default: `false`) |
57
- | `options.lockTimeoutMs` | `number` | Lock acquisition timeout (ms) |
58
- | `options.force` | `"stale_only"` | Force-open when a stale lock exists |
59
- | `options.forceWritable` | `boolean` | Force writable open (dangerous) |
60
- | `options.memvidApiKey` | `string` | Memvid API key for capacity beyond free tier (`mv2_*`) |
61
-
62
- ### Storing documents
63
-
64
- ```typescript
71
+ ### Storing Documents
72
+
73
+ ```javascript
74
+ // Store text content
65
75
  await mv.put({
66
- title: "Document title",
67
- label: "category",
68
- text: "Document content...",
69
- metadata: { key: "value" },
70
- uri: "mv2://custom/path",
71
- tags: ["tag1", "tag2"],
76
+ title: "Meeting Notes",
77
+ label: "meeting",
78
+ text: "Discussed the new API design.",
79
+ metadata: { date: "2024-01-15", priority: "high" },
80
+ tags: ["api", "design", "q1"]
72
81
  });
73
- ```
74
82
 
75
- ### Automatic embeddings (optional)
76
-
77
- To enable semantic search without supplying pre-computed vectors, set `enableEmbedding: true` on `put()`:
83
+ // Store a file (PDF, DOCX, TXT, etc.)
84
+ await mv.put({
85
+ title: "Q4 Report",
86
+ label: "reports",
87
+ file: "./documents/q4-report.pdf"
88
+ });
78
89
 
79
- ```typescript
90
+ // Store with both text and file
80
91
  await mv.put({
81
- title: "Document title",
82
- label: "category",
83
- text: "Document content...",
84
- enableEmbedding: true,
85
- // Optional (defaults to "bge-small")
86
- embeddingModel: "bge-small", // or "openai-small"
92
+ title: "Contract Summary",
93
+ label: "legal",
94
+ text: "Key terms: 2-year agreement, auto-renewal clause.",
95
+ file: "./contracts/agreement.pdf"
87
96
  });
88
97
  ```
89
98
 
90
- Notes:
91
- - Local embedding models use `fastembed` and cache weights under `MEMVID_MODELS_DIR` (first run may download).
92
- - OpenAI embedding models require `OPENAI_API_KEY` (and optionally `OPENAI_BASE_URL`).
93
- - If embeddings cannot be generated, the SDK throws `MV015` (it will not silently ingest without embeddings).
94
-
95
- ### Batch ingestion
99
+ ### Batch Ingestion
96
100
 
97
- For bulk imports, `putMany` processes documents in parallel:
101
+ For large imports, `putMany` is significantly faster:
98
102
 
99
- ```typescript
100
- const docs = [
101
- { title: "Doc 1", text: "First document content..." },
102
- { title: "Doc 2", text: "Second document content..." },
103
+ ```javascript
104
+ const documents = [
105
+ { title: "Doc 1", label: "notes", text: "First document content..." },
106
+ { title: "Doc 2", label: "notes", text: "Second document content..." },
103
107
  // ... thousands more
104
108
  ];
105
109
 
106
- const frameIds = await mv.putMany(docs, { compressionLevel: 3 });
107
- console.log(`Ingested ${frameIds.length} documents`);
110
+ const frameIds = await mv.putMany(documents);
111
+ console.log(`Added ${frameIds.length} documents`);
108
112
  ```
109
113
 
110
- To auto-generate embeddings during batch ingest, enable embeddings in the options (requests that already include `embedding` are left unchanged):
111
-
112
- ```typescript
113
- await mv.putMany(docs, {
114
- enableEmbedding: true,
115
- embeddingModel: "bge-small", // or "openai-small"
116
- });
117
- ```
118
-
119
- If you provide **pre-computed embeddings**, also attach the embedding identity so the CLI/SDKs can auto-detect the correct query embedding model later:
114
+ ### Searching
120
115
 
121
- ```typescript
122
- import { OpenAIEmbeddings } from "@memvid/sdk";
116
+ ```javascript
117
+ // Lexical search (BM25 ranking)
118
+ const results = await mv.find("machine learning", { k: 10 });
123
119
 
124
- const embedder = new OpenAIEmbeddings({ model: "text-embedding-3-small" });
125
- const vectors = await embedder.embedDocuments(docs.map((d) => d.text));
126
-
127
- await mv.putMany(
128
- docs.map((doc, i) => ({
129
- ...doc,
130
- embedding: vectors[i],
131
- embeddingIdentity: {
132
- provider: "openai",
133
- model: embedder.modelName,
134
- dimension: embedder.dimension,
135
- },
136
- }))
137
- );
120
+ for (const hit of results.hits) {
121
+ console.log(`${hit.title}: ${hit.snippet}`);
122
+ }
138
123
  ```
139
124
 
140
- ### External embedding providers (bring your own)
125
+ Search options:
141
126
 
142
- For developer-friendly “use any embedding model/API” workflows, pass an `embedder`:
127
+ | Option | Type | Description |
128
+ |--------|------|-------------|
129
+ | `k` | number | Number of results (default: 10) |
130
+ | `snippetChars` | number | Snippet length (default: 240) |
131
+ | `mode` | string | `"lex"`, `"sem"`, or `"auto"` |
132
+ | `scope` | string | Filter by URI prefix |
143
133
 
144
- ```typescript
145
- import { OpenAIEmbeddings } from "@memvid/sdk";
134
+ ### Semantic Search
146
135
 
147
- const embedder = new OpenAIEmbeddings({ model: "text-embedding-3-small" });
136
+ Semantic search requires embeddings. You can generate them during ingestion:
148
137
 
149
- // Ingest: computes embeddings for requests that omit `embedding` and stores embedding identity metadata.
150
- await mv.putMany(docs, { embedder });
138
+ ```javascript
139
+ // Using local embeddings (bge-small, nomic, etc.)
140
+ await mv.put({
141
+ title: "Document",
142
+ text: "Content here...",
143
+ enableEmbedding: true,
144
+ embeddingModel: "bge-small"
145
+ });
151
146
 
152
- // Query: computes query embeddings when `queryEmbedding` is omitted.
153
- const results = await mv.find("timeline", { mode: "sem", embedder });
154
- const context = await mv.ask("What happened?", { mode: "sem", contextOnly: true, embedder });
147
+ // Using OpenAI embeddings
148
+ await mv.put({
149
+ title: "Document",
150
+ text: "Content here...",
151
+ enableEmbedding: true,
152
+ embeddingModel: "openai-small" // requires OPENAI_API_KEY
153
+ });
155
154
  ```
156
155
 
157
- Built-in external providers (API keys via env vars):
158
- - `OpenAIEmbeddings` (`OPENAI_API_KEY`)
159
- - `CohereEmbeddings` (`COHERE_API_KEY`)
160
- - `VoyageEmbeddings` (`VOYAGE_API_KEY`)
161
- - `NvidiaEmbeddings` (`NVIDIA_API_KEY`, default base URL `https://integrate.api.nvidia.com`)
162
-
163
- Notes:
164
- - If `embedder` is set, `putMany({ enableEmbedding: true })` is ignored (embeddings are computed in JS).
165
- - `put()` does not accept pre-computed vectors; use `putMany([singleDoc], { embedder })` for external embeddings.
156
+ Then search semantically:
166
157
 
167
- ### Searching
168
-
169
- ```typescript
170
- const results = await mv.find(query, options?)
158
+ ```javascript
159
+ const results = await mv.find("neural networks", { mode: "sem" });
171
160
  ```
172
161
 
173
- | Option | Type | Description |
174
- |--------|------|-------------|
175
- | `mode` | `"lex" \| "sem" \| "auto"` | Search mode (default: `"lex"`). `"sem"` uses vector search. `"auto"` reranks lexical hits when embeddings are available. |
176
- | `queryEmbedding` | `number[]` | Pre-computed query embedding (offline-safe). If omitted, the SDK tries to auto-detect the embedding model from the `.mv2` and embed the query. |
177
- | `queryEmbeddingModel` | `string` | Override the query embedding model (e.g. `"openai-small"`, `"bge-small"`). |
178
- | `k` | `number` | Number of results (default: `10`) |
179
- | `snippetChars` | `number` | Snippet length (default: `240`) |
180
- | `scope` | `string` | Filter by URI prefix |
181
- | `adaptive` | `boolean` | Enable adaptive retrieval (semantic-only) |
182
- | `minRelevancy` | `number` | Minimum relevancy ratio vs top score (default: `0.5`, adaptive-only) |
183
- | `maxK` | `number` | Max candidates to consider (default: `100`, adaptive-only) |
184
- | `adaptiveStrategy` | `"relative" \| "absolute" \| "cliff" \| "elbow" \| "combined"` | Adaptive cutoff strategy (default: `"relative"`, adaptive-only) |
185
-
186
- ### Vector search (pre-computed query embedding)
187
-
188
- Use `vecSearch()` when you already have a query embedding vector (offline-safe):
189
-
190
- ```typescript
191
- const queryEmbedding = [/* ... floats ... */];
192
- const results = await mv.vecSearch("my query", queryEmbedding, { k: 10 });
193
- console.log(results.hits);
194
- ```
162
+ **Windows users:** Local embedding models (bge-small, nomic, etc.) are not available on Windows due to ONNX runtime limitations. Use OpenAI embeddings instead by setting `OPENAI_API_KEY`.
195
163
 
196
- ### Retrieval-augmented generation
164
+ ### Question Answering (RAG)
197
165
 
198
- ```typescript
199
- const response = await mv.ask(question, options?)
200
- ```
166
+ ```javascript
167
+ // Basic RAG query
168
+ const answer = await mv.ask("What did we decide about the database?");
169
+ console.log(answer.text);
201
170
 
202
- | Option | Type | Description |
203
- |--------|------|-------------|
204
- | `k` | `number` | Documents to retrieve (default: `6`) |
205
- | `mode` | `string` | `"lex"`, `"sem"`, or `"auto"`/`"hybrid"` |
206
- | `queryEmbedding` | `number[]` | Pre-computed query embedding for semantic/hybrid ask (offline-safe). If omitted, the SDK tries to auto-detect the embedding model from the `.mv2` and embed the query. |
207
- | `queryEmbeddingModel` | `string` | Override the query embedding model (e.g. `"openai-small"`, `"bge-small"`). |
208
- | `adaptive` | `boolean` | Enable adaptive retrieval (semantic/hybrid only) |
209
- | `minRelevancy` | `number` | Minimum relevancy ratio vs top score (default: `0.5`, adaptive-only) |
210
- | `maxK` | `number` | Max candidates to consider (default: `100`, adaptive-only) |
211
- | `adaptiveStrategy` | `"relative" \| "absolute" \| "cliff" \| "elbow" \| "combined"` | Adaptive cutoff strategy (default: `"relative"`, adaptive-only) |
212
-
213
- ### Best practices: Adaptive retrieval
214
-
215
- For best search quality, enable adaptive retrieval with the `combined` strategy. This dynamically adjusts result counts based on relevance scores rather than returning a fixed `k`:
216
-
217
- ```typescript
218
- // Recommended for find()
219
- const results = await mv.find("your query", {
220
- mode: "sem", // or "auto"
221
- adaptive: true,
222
- adaptiveStrategy: "combined",
171
+ // With specific model
172
+ const answer = await mv.ask("Summarize the meeting notes", {
173
+ model: "openai:gpt-4o-mini",
174
+ k: 6 // number of documents to retrieve
223
175
  });
224
176
 
225
- // Recommended for ask()
226
- const answer = await mv.ask("your question", {
227
- mode: "auto",
228
- adaptive: true,
229
- adaptiveStrategy: "combined",
230
- });
177
+ // Get context only (no LLM synthesis)
178
+ const context = await mv.ask("What was discussed?", { contextOnly: true });
179
+ console.log(context.context); // Retrieved document snippets
231
180
  ```
232
181
 
233
- The `combined` strategy uses both relative thresholds and score cliff detection to filter out low-relevance results, providing higher quality context for RAG applications.
182
+ ### Timeline and Stats
234
183
 
235
- ### LLM synthesis options
184
+ ```javascript
185
+ // Get recent entries
186
+ const entries = await mv.timeline({ limit: 20 });
236
187
 
237
- | Option | Type | Description |
238
- |--------|------|-------------|
239
- | `model` | `string` | LLM for synthesis (e.g., `"openai:gpt-4o-mini"`, `"nvidia:meta/llama3-8b-instruct"`) |
240
- | `modelApiKey` | `string` | API key for the LLM provider |
241
- | `contextOnly` | `boolean` | Skip synthesis, return context only |
242
- | `returnSources` | `boolean` | Include source metadata in response |
243
-
244
- ### Timeline queries
245
-
246
- ```typescript
247
- const entries = await mv.timeline({
248
- limit: 50,
249
- since: 1704067200, // Unix timestamp
250
- reverse: true,
251
- });
188
+ // Get statistics
189
+ const stats = await mv.stats();
190
+ console.log(`Documents: ${stats.frame_count}`);
191
+ console.log(`Size: ${stats.size_bytes} bytes`);
252
192
  ```
253
193
 
254
- ### Statistics
194
+ ### Closing
255
195
 
256
- ```typescript
257
- const stats = await mv.stats();
258
- // { frame_count, size_bytes, has_lex_index, has_vec_index, ... }
196
+ Always close the memory when done:
197
+
198
+ ```javascript
199
+ await mv.seal();
259
200
  ```
260
201
 
261
- ### File operations
202
+ ## External Embeddings
262
203
 
263
- ```typescript
264
- // Commit pending changes
265
- await mv.seal();
204
+ For more control over embeddings, use external providers:
205
+
206
+ ```javascript
207
+ import { create, OpenAIEmbeddings, getEmbedder } from "@memvid/sdk";
266
208
 
267
- // Verify file integrity
268
- import { verifyMemvid } from "@memvid/sdk";
269
- const report = await verifyMemvid("notes.mv2", { deep: true });
209
+ // Create memory file
210
+ const mv = await create("knowledge.mv2");
270
211
 
271
- // Repair indexes
272
- import { doctorMemvid } from "@memvid/sdk";
273
- await doctorMemvid("notes.mv2", { rebuildLexIndex: true, dryRun: true });
212
+ // Initialize embedding provider
213
+ const embedder = new OpenAIEmbeddings({ model: "text-embedding-3-small" });
214
+
215
+ // Prepare documents
216
+ const documents = [
217
+ { title: "ML Basics", label: "ai", text: "Machine learning enables systems to learn from data." },
218
+ { title: "Deep Learning", label: "ai", text: "Deep learning uses neural networks with multiple layers." },
219
+ ];
274
220
 
275
- // Verify the single-file guarantee (no sidecar files like -wal/-shm)
276
- import { verifySingleFile } from "@memvid/sdk";
277
- await verifySingleFile("notes.mv2");
221
+ // Ingest with external embeddings
222
+ await mv.putMany(documents, { embedder });
278
223
 
279
- // Lock visibility helpers
280
- import { lockWho, lockNudge } from "@memvid/sdk";
281
- console.log(await lockWho("notes.mv2")); // { locked: false } or { locked: true, owner: ... }
282
- await lockNudge("notes.mv2"); // sends SIGUSR1 to active writer (Unix)
224
+ // Search using external embeddings
225
+ const results = await mv.find("neural networks", { mode: "sem", k: 3, embedder });
226
+
227
+ for (const hit of results.hits) {
228
+ console.log(`${hit.title}: ${hit.score.toFixed(3)}`);
229
+ }
283
230
  ```
284
231
 
285
- ## Framework adapters
232
+ Built-in providers:
233
+ - `OpenAIEmbeddings` (requires `OPENAI_API_KEY`)
234
+ - `CohereEmbeddings` (requires `COHERE_API_KEY`)
235
+ - `VoyageEmbeddings` (requires `VOYAGE_API_KEY`)
236
+ - `NvidiaEmbeddings` (requires `NVIDIA_API_KEY`)
237
+ - `GeminiEmbeddings` (requires `GOOGLE_API_KEY` or `GEMINI_API_KEY`)
238
+ - `MistralEmbeddings` (requires `MISTRAL_API_KEY`)
286
239
 
287
- Adapters expose framework-native tools when the corresponding dependency is installed.
240
+ Use the factory function for quick setup:
241
+
242
+ ```javascript
243
+ import { getEmbedder } from "@memvid/sdk";
244
+
245
+ // Create any supported provider
246
+ const embedder = getEmbedder("openai"); // or "cohere", "voyage", "nvidia", "gemini", "mistral"
247
+ ```
248
+
249
+ ## Framework Integrations
288
250
 
289
251
  ### LangChain
290
252
 
291
- ```typescript
253
+ ```javascript
292
254
  import { use } from "@memvid/sdk";
293
255
 
294
256
  const mv = await use("langchain", "notes.mv2");
295
- const tools = mv.tools; // StructuredTool instances for put/find/ask
257
+ const tools = mv.tools; // StructuredTool instances for agents
296
258
  ```
297
259
 
298
260
  ### LlamaIndex
299
261
 
300
- ```typescript
262
+ ```javascript
301
263
  const mv = await use("llamaindex", "notes.mv2");
302
- const queryEngine = mv.asQueryEngine();
264
+ const engine = mv.asQueryEngine();
265
+ const response = await engine.query("What is the timeline?");
303
266
  ```
304
267
 
305
- ### OpenAI function calling
268
+ ### OpenAI Function Calling
306
269
 
307
- ```typescript
270
+ ```javascript
308
271
  const mv = await use("openai", "notes.mv2");
309
- const functions = mv.functions; // JSON schemas for tool_calls
272
+ const functions = mv.functions; // JSON schemas for tool_calls
310
273
  ```
311
274
 
312
275
  ### Vercel AI SDK
313
276
 
314
- ```typescript
277
+ ```javascript
315
278
  const mv = await use("vercel-ai", "notes.mv2");
316
279
  ```
317
280
 
318
- ## Table extraction
319
-
320
- Extract structured tables from PDFs:
281
+ ## Error Handling
321
282
 
322
- ```typescript
323
- const result = await mv.putPdfTables("report.pdf", true);
324
- console.log(`Extracted ${result.tables_count} tables`);
283
+ Errors include a code for programmatic handling:
325
284
 
326
- const tables = await mv.listTables();
327
- const data = await mv.getTable(tables[0].table_id, "json");
328
- ```
329
-
330
- ## Error handling
331
-
332
- Errors include a code prefix for programmatic handling:
333
-
334
- | Code | Description |
335
- |------|-------------|
336
- | `MV001` | Storage capacity exceeded |
337
- | `MV002` | Invalid ticket signature |
338
- | `MV003` | Ticket replay detected |
339
- | `MV004` | Lexical index not enabled |
340
- | `MV005` | Time index missing |
341
- | `MV006` | Verification failed |
342
- | `MV007` | File locked by another process |
343
- | `MV008` | Memvid API key required |
344
- | `MV009` | Memory already bound |
345
- | `MV010` | Frame not found |
346
- | `MV011` | Vector index not enabled |
347
- | `MV012` | Corrupt file detected |
348
- | `MV013` | I/O error (e.g., file not found) |
349
- | `MV014` | Vector dimension mismatch |
350
- | `MV015` | Embedding runtime unavailable/failed |
351
- | `MV999` | Unknown/internal error |
352
-
353
- ```typescript
285
+ ```javascript
354
286
  import { MemvidError } from "@memvid/sdk";
355
287
 
356
288
  try {
357
- await mv.put({ ... });
289
+ await mv.put({ title: "Doc", text: "Content" });
358
290
  } catch (err) {
359
291
  if (err instanceof MemvidError) {
360
- if (err.code === "MV001") {
361
- console.error("Out of storage capacity");
362
- } else {
363
- console.error(`Error ${err.code}: ${err.message}`);
292
+ switch (err.code) {
293
+ case "MV001": console.error("Storage capacity exceeded"); break;
294
+ case "MV007": console.error("File is locked"); break;
295
+ case "MV015": console.error("Embedding failed"); break;
296
+ default: console.error(`Error ${err.code}: ${err.message}`);
364
297
  }
365
298
  }
366
299
  }
367
300
  ```
368
301
 
369
- ## Environment variables
302
+ Common error codes:
370
303
 
371
- | Variable | Description |
372
- |----------|-------------|
373
- | `MEMVID_API_KEY` | API key for capacity beyond free tier |
374
- | `MEMVID_API_URL` | Control plane URL (for enterprise deployments) |
375
- | `MEMVID_MODELS_DIR` | Path to embedding model cache |
376
- | `MEMVID_OFFLINE` | Set to `1` to disable network-backed embeddings and avoid model downloads |
377
- | `OPENAI_API_KEY` | API key for OpenAI embeddings / LLMs (when used) |
378
- | `OPENAI_BASE_URL` | Override OpenAI API base URL (defaults to `https://api.openai.com`) |
304
+ | Code | Description |
305
+ |------|-------------|
306
+ | MV001 | Storage capacity exceeded |
307
+ | MV007 | File locked by another process |
308
+ | MV010 | Frame not found |
309
+ | MV013 | File not found |
310
+ | MV015 | Embedding failed |
379
311
 
380
- ## Building from source
312
+ ## Environment Variables
381
313
 
382
- ```bash
383
- # Install dependencies
384
- pnpm install
314
+ | Variable | Description |
315
+ |----------|-------------|
316
+ | `OPENAI_API_KEY` | For OpenAI embeddings and LLM synthesis |
317
+ | `OPENAI_BASE_URL` | Custom OpenAI-compatible endpoint |
318
+ | `NVIDIA_API_KEY` | For NVIDIA NIM embeddings |
319
+ | `MEMVID_MODELS_DIR` | Local embedding model cache directory |
320
+ | `MEMVID_API_KEY` | For capacity beyond the free tier |
321
+ | `MEMVID_OFFLINE` | Set to `1` to disable network features |
322
+
323
+ ## Platform Support
324
+
325
+ | Platform | Architecture | Local Embeddings |
326
+ |----------|--------------|------------------|
327
+ | macOS | ARM64 (Apple Silicon) | Yes |
328
+ | macOS | x64 (Intel) | Yes |
329
+ | Linux | x64 (glibc) | Yes |
330
+ | Windows | x64 | No (use OpenAI) |
385
331
 
386
- # Build TypeScript
387
- pnpm run build
332
+ ## Requirements
388
333
 
389
- # Build native module (requires Rust toolchain)
390
- cargo build --release
391
- cp target/release/libmemvid_node.dylib index.node # macOS
392
- ```
334
+ - Node.js 18 or later
335
+ - For local embeddings: macOS or Linux (Windows requires OpenAI)
393
336
 
394
- ## Requirements
337
+ ## More Information
395
338
 
396
- - Node.js 18+
397
- - macOS (Apple Silicon or Intel), Linux (x64), or Windows (x64)
339
+ - Documentation: https://docs.memvid.com
340
+ - GitHub: https://github.com/memvid/memvid
341
+ - Discord: https://discord.gg/2mynS7fcK7
342
+ - Website: https://memvid.com
398
343
 
399
344
  ## License
400
345
 
401
- Apache-2.0. See [LICENSE](./LICENSE).
346
+ Apache-2.0
package/dist/index.js CHANGED
@@ -488,16 +488,26 @@ function loadNativeAddon() {
488
488
  }
489
489
  // Production mode: load from platform-specific package
490
490
  if (platformInfo) {
491
+ // Split scoped package name: "@memvid/sdk-win32-x64-msvc" -> ["@memvid", "sdk-win32-x64-msvc"]
492
+ const pkgParts = platformInfo.pkg.split("/");
493
+ const scope = pkgParts[0]; // "@memvid"
494
+ const pkgName = pkgParts[1]; // "sdk-win32-x64-msvc"
491
495
  // Try to find the platform package in various locations
492
496
  const possiblePaths = [
493
- // Standard npm install location
494
- path.join(__dirname, "..", "node_modules", platformInfo.pkg, platformInfo.binary),
495
- // Hoisted to parent node_modules
496
- path.join(__dirname, "..", "..", platformInfo.pkg, platformInfo.binary),
497
+ // Sibling in same scope (most common for scoped packages)
498
+ // From @memvid/sdk/dist -> @memvid/sdk-win32-x64-msvc
499
+ path.join(__dirname, "..", "..", pkgName, platformInfo.binary),
500
+ // Standard npm install location (nested node_modules)
501
+ path.join(__dirname, "..", "node_modules", scope, pkgName, platformInfo.binary),
497
502
  // Hoisted to root node_modules
498
- path.join(__dirname, "..", "..", "..", platformInfo.pkg, platformInfo.binary),
503
+ // From @memvid/sdk/dist -> ../../.. = node_modules, then @memvid/sdk-win32-x64-msvc
504
+ path.join(__dirname, "..", "..", "..", scope, pkgName, platformInfo.binary),
505
+ // Hoisted 4 levels up (deep yarn workspaces)
506
+ path.join(__dirname, "..", "..", "..", "..", scope, pkgName, platformInfo.binary),
499
507
  // pnpm structure
500
- path.join(__dirname, "..", "..", ".pnpm", "node_modules", platformInfo.pkg, platformInfo.binary),
508
+ path.join(__dirname, "..", "..", ".pnpm", "node_modules", scope, pkgName, platformInfo.binary),
509
+ // Yarn PnP / berry
510
+ path.join(__dirname, "..", "..", ".yarn", "cache", `${scope.replace("@", "")}-${pkgName}`, platformInfo.binary),
501
511
  ];
502
512
  for (const binaryPath of possiblePaths) {
503
513
  try {
@@ -542,6 +552,17 @@ function loadNativeAddon() {
542
552
  }
543
553
  // No platform package found
544
554
  const supportedPlatforms = Object.keys(platformPackages).join(", ");
555
+ const platformPkg = platformInfo?.pkg;
556
+ if (platformPkg) {
557
+ // Platform is supported but binary not found
558
+ throw new Error(`Native binary not found for platform: ${key}\n` +
559
+ `The platform package ${platformPkg} may not have installed correctly.\n` +
560
+ `Try reinstalling:\n` +
561
+ ` npm install ${platformPkg}\n` +
562
+ ` # or: yarn add ${platformPkg}\n` +
563
+ `Then reinstall the main package:\n` +
564
+ ` npm install @memvid/sdk`);
565
+ }
545
566
  throw new Error(`Unsupported platform: ${key}\n` +
546
567
  `Supported platforms: ${supportedPlatforms}\n` +
547
568
  `Make sure you have installed @memvid/sdk correctly:\n` +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memvid/sdk",
3
- "version": "2.0.140",
3
+ "version": "2.0.143",
4
4
  "description": "Single-file AI memory system for Node.js. Store, search, and query documents with built-in RAG.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -41,10 +41,10 @@
41
41
  "node": ">=18"
42
42
  },
43
43
  "optionalDependencies": {
44
- "@memvid/sdk-darwin-arm64": "2.0.140",
45
- "@memvid/sdk-darwin-x64": "2.0.140",
46
- "@memvid/sdk-linux-x64-gnu": "2.0.140",
47
- "@memvid/sdk-win32-x64-msvc": "2.0.140"
44
+ "@memvid/sdk-darwin-arm64": "2.0.143",
45
+ "@memvid/sdk-darwin-x64": "2.0.143",
46
+ "@memvid/sdk-linux-x64-gnu": "2.0.143",
47
+ "@memvid/sdk-win32-x64-msvc": "2.0.143"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "@langchain/core": ">=0.3.0",