@memvid/sdk 2.0.143 → 2.0.145

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.d.ts CHANGED
@@ -300,7 +300,7 @@ export declare function create(filename: string, kind?: Kind, apiKeyOrOptions?:
300
300
  export declare function open(filename: string, kind?: Kind, apiKeyOrOptions?: ApiKey | UseOptions, options?: UseOptions): Promise<Memvid>;
301
301
  export declare function verifyMemvid(path: string, options?: UseVerifyOptions): Promise<unknown>;
302
302
  export declare function doctorMemvid(path: string, options?: UseDoctorOptions): Promise<unknown>;
303
- export type { AddMemoryCardsResult, Kind, ApiKey, Memvid, MemoryCard, MemoryCardInput, MemoriesResult, MemoriesStats, LockOptions, UseOptions, UnlockOptions, FindInput, VecSearchInput, AskInput, TimelineInput, PutInput, PutManyInput, PutManyOptions, MemvidErrorCode, MemvidErrorDetails, HeatmapEntry, HeatmapResponse, SessionSummary, SessionReplayResult, SessionActionResult, StatsResult, FindHit, FindResult, VecSearchResult, AskResult, AskStats, AskUsage, AskSource, TimelineEntry, } from "./types";
303
+ export type { AddMemoryCardsResult, Kind, ApiKey, Memvid, MemoryCard, MemoryCardInput, MemoriesResult, MemoriesStats, LockOptions, UseOptions, UnlockOptions, FindInput, VecSearchInput, AskInput, TimelineInput, PutInput, PutManyInput, PutManyOptions, MemvidErrorCode, MemvidErrorDetails, HeatmapEntry, HeatmapResponse, SessionSummary, SessionReplayResult, SessionActionResult, StatsResult, FindHit, FindResult, VecSearchResult, AskResult, AskStats, AskUsage, AskSource, Grounding, FollowUp, TimelineEntry, } from "./types";
304
304
  export { MemvidError, CapacityExceededError, TicketInvalidError, TicketReplayError, LexIndexDisabledError, TimeIndexMissingError, VerificationFailedError, LockedError, ApiKeyRequiredError, FileNotFoundError, MemoryAlreadyBoundError, FrameNotFoundError, VecIndexDisabledError, CorruptFileError, VecDimensionMismatchError, EmbeddingFailedError, EncryptionError, QuotaExceededError, getErrorSuggestion, } from "./error";
305
305
  export { EmbeddingProvider, OpenAIEmbeddings, OpenAIEmbeddingsConfig, CohereEmbeddings, CohereEmbeddingsConfig, VoyageEmbeddings, VoyageEmbeddingsConfig, NvidiaEmbeddings, NvidiaEmbeddingsConfig, GeminiEmbeddings, GeminiEmbeddingsConfig, MistralEmbeddings, MistralEmbeddingsConfig, getEmbedder, MODEL_DIMENSIONS, LOCAL_EMBEDDING_MODELS, LocalEmbeddingModel, } from "./embeddings";
306
306
  export { flush as flushAnalytics, isTelemetryEnabled } from "./analytics";
package/dist/index.js CHANGED
@@ -492,6 +492,11 @@ function loadNativeAddon() {
492
492
  const pkgParts = platformInfo.pkg.split("/");
493
493
  const scope = pkgParts[0]; // "@memvid"
494
494
  const pkgName = pkgParts[1]; // "sdk-win32-x64-msvc"
495
+ const debug = process.env.MEMVID_DEBUG === "1";
496
+ if (debug) {
497
+ console.log("[memvid] __dirname:", __dirname);
498
+ console.log("[memvid] Looking for platform package:", platformInfo.pkg);
499
+ }
495
500
  // Try to find the platform package in various locations
496
501
  const possiblePaths = [
497
502
  // Sibling in same scope (most common for scoped packages)
@@ -509,9 +514,16 @@ function loadNativeAddon() {
509
514
  // Yarn PnP / berry
510
515
  path.join(__dirname, "..", "..", ".yarn", "cache", `${scope.replace("@", "")}-${pkgName}`, platformInfo.binary),
511
516
  ];
517
+ if (debug) {
518
+ console.log("[memvid] Checking paths:");
519
+ possiblePaths.forEach((p, i) => console.log(` [${i}] ${p}`));
520
+ }
512
521
  for (const binaryPath of possiblePaths) {
513
522
  try {
514
523
  fs.statSync(binaryPath);
524
+ if (debug) {
525
+ console.log("[memvid] Found binary at:", binaryPath);
526
+ }
515
527
  // Set LD_LIBRARY_PATH/DYLD_LIBRARY_PATH for Tika library
516
528
  const binaryDir = path.dirname(binaryPath);
517
529
  if (platform === "linux") {
@@ -526,7 +538,10 @@ function loadNativeAddon() {
526
538
  }
527
539
  return require(binaryPath);
528
540
  }
529
- catch {
541
+ catch (err) {
542
+ if (debug) {
543
+ console.log(`[memvid] Path not found: ${binaryPath}`);
544
+ }
530
545
  // Try next path
531
546
  }
532
547
  }
@@ -1279,10 +1294,129 @@ class MemvidImpl {
1279
1294
  }
1280
1295
  }
1281
1296
  }
1297
+ // Calculate grounding score
1298
+ this.verifyGrounding(response);
1282
1299
  // Build follow-up suggestions if confidence is low
1283
1300
  return this.buildFollowUp(response);
1284
1301
  });
1285
1302
  }
1303
+ verifyGrounding(response) {
1304
+ const answer = response.answer || "";
1305
+ const context = response.context || "";
1306
+ // Empty answer = no hallucination
1307
+ if (!answer) {
1308
+ response.grounding = {
1309
+ score: 1.0,
1310
+ label: "HIGH",
1311
+ sentence_count: 0,
1312
+ grounded_sentences: 0,
1313
+ has_warning: false,
1314
+ warning_reason: undefined,
1315
+ };
1316
+ return;
1317
+ }
1318
+ // No context = potential hallucination
1319
+ if (!context) {
1320
+ response.grounding = {
1321
+ score: 0.0,
1322
+ label: "LOW",
1323
+ sentence_count: 1,
1324
+ grounded_sentences: 0,
1325
+ has_warning: true,
1326
+ warning_reason: "No context provided - answer may be hallucinated",
1327
+ };
1328
+ return;
1329
+ }
1330
+ // Normalize context for comparison
1331
+ const contextLower = context.toLowerCase();
1332
+ const contextWords = new Set(contextLower.split(/[^a-zA-Z0-9]+/).filter(w => w.length > 2));
1333
+ // Split answer into sentences
1334
+ const sentences = answer
1335
+ .split(/[.!?]/)
1336
+ .map(s => s.trim())
1337
+ .filter(s => s.length > 10);
1338
+ if (sentences.length === 0) {
1339
+ response.grounding = {
1340
+ score: 0.5,
1341
+ label: "MEDIUM",
1342
+ sentence_count: 0,
1343
+ grounded_sentences: 0,
1344
+ has_warning: false,
1345
+ warning_reason: undefined,
1346
+ };
1347
+ return;
1348
+ }
1349
+ const sentenceScores = [];
1350
+ let groundedCount = 0;
1351
+ for (const sentence of sentences) {
1352
+ const sentenceLower = sentence.toLowerCase();
1353
+ const sentenceWords = new Set(sentenceLower.split(/[^a-zA-Z0-9]+/).filter(w => w.length > 2));
1354
+ if (sentenceWords.size === 0) {
1355
+ sentenceScores.push(0.5);
1356
+ continue;
1357
+ }
1358
+ // Calculate word overlap
1359
+ let overlap = 0;
1360
+ for (const word of sentenceWords) {
1361
+ if (contextWords.has(word))
1362
+ overlap++;
1363
+ }
1364
+ const score = overlap / Math.max(sentenceWords.size, 1);
1365
+ // Add phrase bonus for exact matches
1366
+ let phraseBonus = 0;
1367
+ if (contextLower.includes(sentenceLower)) {
1368
+ phraseBonus = 0.3;
1369
+ }
1370
+ else {
1371
+ // Check for significant substring matches
1372
+ const words = sentenceLower.split(/\s+/);
1373
+ if (words.length >= 3) {
1374
+ const phrase = words.slice(0, 3).join(" ");
1375
+ if (contextLower.includes(phrase)) {
1376
+ phraseBonus = 0.15;
1377
+ }
1378
+ }
1379
+ }
1380
+ const finalScore = Math.min(score + phraseBonus, 1.0);
1381
+ sentenceScores.push(finalScore);
1382
+ if (finalScore >= 0.3) {
1383
+ groundedCount++;
1384
+ }
1385
+ }
1386
+ const overallScore = sentenceScores.length > 0
1387
+ ? sentenceScores.reduce((a, b) => a + b, 0) / sentenceScores.length
1388
+ : 0.5;
1389
+ // Determine warning
1390
+ let hasWarning = false;
1391
+ let warningReason;
1392
+ if (overallScore < 0.2) {
1393
+ hasWarning = true;
1394
+ warningReason = "Answer appears to be poorly grounded in context";
1395
+ }
1396
+ else if (overallScore < 0.4 && groundedCount < Math.floor(sentences.length / 2)) {
1397
+ hasWarning = true;
1398
+ warningReason = "Some statements may not be supported by context";
1399
+ }
1400
+ // Determine label
1401
+ let label;
1402
+ if (overallScore >= 0.7) {
1403
+ label = "HIGH";
1404
+ }
1405
+ else if (overallScore >= 0.4) {
1406
+ label = "MEDIUM";
1407
+ }
1408
+ else {
1409
+ label = "LOW";
1410
+ }
1411
+ response.grounding = {
1412
+ score: overallScore,
1413
+ label,
1414
+ sentence_count: sentences.length,
1415
+ grounded_sentences: groundedCount,
1416
+ has_warning: hasWarning,
1417
+ warning_reason: warningReason,
1418
+ };
1419
+ }
1286
1420
  async buildFollowUp(response) {
1287
1421
  const hits = response.hits || [];
1288
1422
  // Check if retrieval has no results
@@ -1296,10 +1430,10 @@ class MemvidImpl {
1296
1430
  veryLowRetrieval = true;
1297
1431
  }
1298
1432
  }
1299
- // Check grounding if available (from model inference)
1300
- const grounding = response.grounding || {};
1301
- const hasGroundingWarning = grounding.has_warning || false;
1302
- const lowGrounding = grounding.score !== undefined && grounding.score < 0.3;
1433
+ // Check grounding if available
1434
+ const grounding = response.grounding;
1435
+ const hasGroundingWarning = grounding?.has_warning || false;
1436
+ const lowGrounding = grounding?.score !== undefined && grounding.score < 0.3;
1303
1437
  // Detect "Not enough information" type answers (primary trigger)
1304
1438
  const answer = (response.answer || "").toLowerCase();
1305
1439
  const noInfoPhrases = [
package/dist/types.d.ts CHANGED
@@ -507,6 +507,21 @@ export interface FollowUp {
507
507
  available_topics: string[];
508
508
  suggestions: string[];
509
509
  }
510
+ /** Grounding information for answer quality assessment */
511
+ export interface Grounding {
512
+ /** Overall grounding score (0-1) */
513
+ score: number;
514
+ /** Grounding quality label (LOW, MEDIUM, HIGH) */
515
+ label?: string;
516
+ /** Number of sentences in the answer */
517
+ sentence_count?: number;
518
+ /** Number of sentences grounded in context */
519
+ grounded_sentences?: number;
520
+ /** Whether there's a grounding warning */
521
+ has_warning: boolean;
522
+ /** Reason for the warning if any */
523
+ warning_reason?: string;
524
+ }
510
525
  /** Response from ask() method */
511
526
  export interface AskResult {
512
527
  question: string;
@@ -521,6 +536,8 @@ export interface AskResult {
521
536
  stats: AskStats;
522
537
  usage: AskUsage;
523
538
  model?: string;
539
+ /** Grounding information for answer quality assessment */
540
+ grounding?: Grounding;
524
541
  /** Follow-up suggestions when confidence is low */
525
542
  follow_up?: FollowUp;
526
543
  }
@@ -548,6 +565,10 @@ export interface Memvid {
548
565
  vecSearch(query: string, queryEmbedding: number[], opts?: VecSearchInput): Promise<VecSearchResult>;
549
566
  /** Ask a question and get an AI-generated answer based on memory contents. */
550
567
  ask(question: string, opts?: AskInput): Promise<AskResult>;
568
+ /** Store a correction/ground truth statement with retrieval priority boost. */
569
+ correct(statement: string, options?: CorrectOptions): Promise<string>;
570
+ /** Batch store multiple corrections with retrieval priority boost. */
571
+ correctMany(corrections: CorrectManyInput[]): Promise<string[]>;
551
572
  /** Get chronological list of frames. */
552
573
  timeline(opts?: TimelineInput): Promise<TimelineEntry[]>;
553
574
  /** Get memory statistics including capacity, frame count, and index status. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memvid/sdk",
3
- "version": "2.0.143",
3
+ "version": "2.0.145",
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.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"
44
+ "@memvid/sdk-darwin-arm64": "2.0.145",
45
+ "@memvid/sdk-darwin-x64": "2.0.145",
46
+ "@memvid/sdk-linux-x64-gnu": "2.0.145",
47
+ "@memvid/sdk-win32-x64-msvc": "2.0.145"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "@langchain/core": ">=0.3.0",