@soulcraft/brainy 0.20.0 → 0.22.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 (83) hide show
  1. package/README.md +1 -1
  2. package/dist/augmentations/conduitAugmentations.js +1158 -0
  3. package/dist/augmentations/conduitAugmentations.js.map +1 -0
  4. package/dist/augmentations/memoryAugmentations.js +255 -0
  5. package/dist/augmentations/memoryAugmentations.js.map +1 -0
  6. package/dist/augmentations/serverSearchAugmentations.js +531 -0
  7. package/dist/augmentations/serverSearchAugmentations.js.map +1 -0
  8. package/dist/coreTypes.d.ts +12 -0
  9. package/dist/examples/basicUsage.js +128 -0
  10. package/dist/examples/basicUsage.js.map +1 -0
  11. package/dist/hnsw/hnswIndex.js +550 -0
  12. package/dist/hnsw/hnswIndex.js.map +1 -0
  13. package/dist/hnsw/hnswIndexOptimized.js +441 -0
  14. package/dist/hnsw/hnswIndexOptimized.js.map +1 -0
  15. package/dist/mcp/brainyMCPAdapter.js +142 -0
  16. package/dist/mcp/brainyMCPAdapter.js.map +1 -0
  17. package/dist/mcp/brainyMCPService.js +248 -0
  18. package/dist/mcp/brainyMCPService.js.map +1 -0
  19. package/dist/mcp/index.js +17 -0
  20. package/dist/mcp/index.js.map +1 -0
  21. package/dist/mcp/mcpAugmentationToolset.js +180 -0
  22. package/dist/mcp/mcpAugmentationToolset.js.map +1 -0
  23. package/dist/storage/adapters/baseStorageAdapter.d.ts +14 -0
  24. package/dist/storage/adapters/baseStorageAdapter.d.ts.map +1 -1
  25. package/dist/storage/adapters/baseStorageAdapter.js +233 -0
  26. package/dist/storage/adapters/baseStorageAdapter.js.map +1 -0
  27. package/dist/storage/adapters/fileSystemStorage.d.ts +27 -27
  28. package/dist/storage/adapters/fileSystemStorage.d.ts.map +1 -1
  29. package/dist/storage/adapters/fileSystemStorage.js +568 -0
  30. package/dist/storage/adapters/fileSystemStorage.js.map +1 -0
  31. package/dist/storage/adapters/memoryStorage.d.ts +27 -27
  32. package/dist/storage/adapters/memoryStorage.d.ts.map +1 -1
  33. package/dist/storage/adapters/memoryStorage.js +300 -0
  34. package/dist/storage/adapters/memoryStorage.js.map +1 -0
  35. package/dist/storage/adapters/opfsStorage.d.ts +64 -6
  36. package/dist/storage/adapters/opfsStorage.d.ts.map +1 -1
  37. package/dist/storage/adapters/opfsStorage.js +778 -0
  38. package/dist/storage/adapters/opfsStorage.js.map +1 -0
  39. package/dist/storage/adapters/s3CompatibleStorage.d.ts +86 -1
  40. package/dist/storage/adapters/s3CompatibleStorage.d.ts.map +1 -1
  41. package/dist/storage/adapters/s3CompatibleStorage.js +1021 -0
  42. package/dist/storage/adapters/s3CompatibleStorage.js.map +1 -0
  43. package/dist/storage/baseStorage.d.ts +24 -24
  44. package/dist/storage/baseStorage.d.ts.map +1 -1
  45. package/dist/storage/baseStorage.js +126 -0
  46. package/dist/storage/baseStorage.js.map +1 -0
  47. package/dist/storage/storageFactory.js +183 -0
  48. package/dist/storage/storageFactory.js.map +1 -0
  49. package/dist/types/augmentations.js +16 -0
  50. package/dist/types/augmentations.js.map +1 -0
  51. package/dist/types/brainyDataInterface.js +8 -0
  52. package/dist/types/brainyDataInterface.js.map +1 -0
  53. package/dist/types/fileSystemTypes.js +8 -0
  54. package/dist/types/fileSystemTypes.js.map +1 -0
  55. package/dist/types/graphTypes.d.ts +2 -1
  56. package/dist/types/graphTypes.d.ts.map +1 -1
  57. package/dist/types/graphTypes.js +36 -0
  58. package/dist/types/graphTypes.js.map +1 -0
  59. package/dist/types/mcpTypes.js +22 -0
  60. package/dist/types/mcpTypes.js.map +1 -0
  61. package/dist/types/pipelineTypes.js +7 -0
  62. package/dist/types/pipelineTypes.js.map +1 -0
  63. package/dist/types/tensorflowTypes.js +6 -0
  64. package/dist/types/tensorflowTypes.js.map +1 -0
  65. package/dist/unified.js +983 -336
  66. package/dist/unified.min.js +623 -623
  67. package/dist/utils/distance.js +239 -0
  68. package/dist/utils/distance.js.map +1 -0
  69. package/dist/utils/embedding.js +622 -0
  70. package/dist/utils/embedding.js.map +1 -0
  71. package/dist/utils/environment.js +75 -0
  72. package/dist/utils/environment.js.map +1 -0
  73. package/dist/utils/index.js +5 -0
  74. package/dist/utils/index.js.map +1 -0
  75. package/dist/utils/statistics.js +25 -0
  76. package/dist/utils/statistics.js.map +1 -0
  77. package/dist/utils/tensorflowUtils.js +25 -0
  78. package/dist/utils/tensorflowUtils.js.map +1 -0
  79. package/dist/utils/textEncoding.js +281 -0
  80. package/dist/utils/textEncoding.js.map +1 -0
  81. package/dist/utils/workerUtils.js +458 -0
  82. package/dist/utils/workerUtils.js.map +1 -0
  83. package/package.json +4 -3
package/dist/unified.js CHANGED
@@ -5195,19 +5195,115 @@ class HNSWIndexOptimized extends HNSWIndex {
5195
5195
  * Base class for storage adapters that implements statistics tracking
5196
5196
  */
5197
5197
  class BaseStorageAdapter {
5198
+ constructor() {
5199
+ // Statistics cache
5200
+ this.statisticsCache = null;
5201
+ // Batch update timer ID
5202
+ this.statisticsBatchUpdateTimerId = null;
5203
+ // Flag to indicate if statistics have been modified since last save
5204
+ this.statisticsModified = false;
5205
+ // Time of last statistics flush to storage
5206
+ this.lastStatisticsFlushTime = 0;
5207
+ // Minimum time between statistics flushes (5 seconds)
5208
+ this.MIN_FLUSH_INTERVAL_MS = 5000;
5209
+ // Maximum time to wait before flushing statistics (30 seconds)
5210
+ this.MAX_FLUSH_DELAY_MS = 30000;
5211
+ }
5198
5212
  /**
5199
5213
  * Save statistics data
5200
5214
  * @param statistics The statistics data to save
5201
5215
  */
5202
5216
  async saveStatistics(statistics) {
5203
- await this.saveStatisticsData(statistics);
5217
+ // Update the cache with a deep copy to avoid reference issues
5218
+ this.statisticsCache = {
5219
+ nounCount: { ...statistics.nounCount },
5220
+ verbCount: { ...statistics.verbCount },
5221
+ metadataCount: { ...statistics.metadataCount },
5222
+ hnswIndexSize: statistics.hnswIndexSize,
5223
+ lastUpdated: statistics.lastUpdated
5224
+ };
5225
+ // Schedule a batch update instead of saving immediately
5226
+ this.scheduleBatchUpdate();
5204
5227
  }
5205
5228
  /**
5206
5229
  * Get statistics data
5207
5230
  * @returns Promise that resolves to the statistics data
5208
5231
  */
5209
5232
  async getStatistics() {
5210
- return await this.getStatisticsData();
5233
+ // If we have cached statistics, return a deep copy
5234
+ if (this.statisticsCache) {
5235
+ return {
5236
+ nounCount: { ...this.statisticsCache.nounCount },
5237
+ verbCount: { ...this.statisticsCache.verbCount },
5238
+ metadataCount: { ...this.statisticsCache.metadataCount },
5239
+ hnswIndexSize: this.statisticsCache.hnswIndexSize,
5240
+ lastUpdated: this.statisticsCache.lastUpdated
5241
+ };
5242
+ }
5243
+ // Otherwise, get from storage
5244
+ const statistics = await this.getStatisticsData();
5245
+ // If we found statistics, update the cache
5246
+ if (statistics) {
5247
+ // Update the cache with a deep copy
5248
+ this.statisticsCache = {
5249
+ nounCount: { ...statistics.nounCount },
5250
+ verbCount: { ...statistics.verbCount },
5251
+ metadataCount: { ...statistics.metadataCount },
5252
+ hnswIndexSize: statistics.hnswIndexSize,
5253
+ lastUpdated: statistics.lastUpdated
5254
+ };
5255
+ }
5256
+ return statistics;
5257
+ }
5258
+ /**
5259
+ * Schedule a batch update of statistics
5260
+ */
5261
+ scheduleBatchUpdate() {
5262
+ // Mark statistics as modified
5263
+ this.statisticsModified = true;
5264
+ // If a timer is already set, don't set another one
5265
+ if (this.statisticsBatchUpdateTimerId !== null) {
5266
+ return;
5267
+ }
5268
+ // Calculate time since last flush
5269
+ const now = Date.now();
5270
+ const timeSinceLastFlush = now - this.lastStatisticsFlushTime;
5271
+ // If we've recently flushed, wait longer before the next flush
5272
+ const delayMs = timeSinceLastFlush < this.MIN_FLUSH_INTERVAL_MS
5273
+ ? this.MAX_FLUSH_DELAY_MS
5274
+ : this.MIN_FLUSH_INTERVAL_MS;
5275
+ // Schedule the batch update
5276
+ this.statisticsBatchUpdateTimerId = setTimeout(() => {
5277
+ this.flushStatistics();
5278
+ }, delayMs);
5279
+ }
5280
+ /**
5281
+ * Flush statistics to storage
5282
+ */
5283
+ async flushStatistics() {
5284
+ // Clear the timer
5285
+ if (this.statisticsBatchUpdateTimerId !== null) {
5286
+ clearTimeout(this.statisticsBatchUpdateTimerId);
5287
+ this.statisticsBatchUpdateTimerId = null;
5288
+ }
5289
+ // If statistics haven't been modified, no need to flush
5290
+ if (!this.statisticsModified || !this.statisticsCache) {
5291
+ return;
5292
+ }
5293
+ try {
5294
+ // Save the statistics to storage
5295
+ await this.saveStatisticsData(this.statisticsCache);
5296
+ // Update the last flush time
5297
+ this.lastStatisticsFlushTime = Date.now();
5298
+ // Reset the modified flag
5299
+ this.statisticsModified = false;
5300
+ }
5301
+ catch (error) {
5302
+ console.error('Failed to flush statistics data:', error);
5303
+ // Mark as still modified so we'll try again later
5304
+ this.statisticsModified = true;
5305
+ // Don't throw the error to avoid disrupting the application
5306
+ }
5211
5307
  }
5212
5308
  /**
5213
5309
  * Increment a statistic counter
@@ -5216,23 +5312,34 @@ class BaseStorageAdapter {
5216
5312
  * @param amount The amount to increment by (default: 1)
5217
5313
  */
5218
5314
  async incrementStatistic(type, service, amount = 1) {
5219
- // Get current statistics or create default if not exists
5220
- let statistics = await this.getStatisticsData();
5315
+ // Get current statistics from cache or storage
5316
+ let statistics = this.statisticsCache;
5221
5317
  if (!statistics) {
5222
- statistics = this.createDefaultStatistics();
5318
+ statistics = await this.getStatisticsData();
5319
+ if (!statistics) {
5320
+ statistics = this.createDefaultStatistics();
5321
+ }
5322
+ // Update the cache
5323
+ this.statisticsCache = {
5324
+ nounCount: { ...statistics.nounCount },
5325
+ verbCount: { ...statistics.verbCount },
5326
+ metadataCount: { ...statistics.metadataCount },
5327
+ hnswIndexSize: statistics.hnswIndexSize,
5328
+ lastUpdated: statistics.lastUpdated
5329
+ };
5223
5330
  }
5224
5331
  // Increment the appropriate counter
5225
5332
  const counterMap = {
5226
- noun: statistics.nounCount,
5227
- verb: statistics.verbCount,
5228
- metadata: statistics.metadataCount
5333
+ noun: this.statisticsCache.nounCount,
5334
+ verb: this.statisticsCache.verbCount,
5335
+ metadata: this.statisticsCache.metadataCount
5229
5336
  };
5230
5337
  const counter = counterMap[type];
5231
5338
  counter[service] = (counter[service] || 0) + amount;
5232
5339
  // Update timestamp
5233
- statistics.lastUpdated = new Date().toISOString();
5234
- // Save updated statistics
5235
- await this.saveStatisticsData(statistics);
5340
+ this.statisticsCache.lastUpdated = new Date().toISOString();
5341
+ // Schedule a batch update instead of saving immediately
5342
+ this.scheduleBatchUpdate();
5236
5343
  }
5237
5344
  /**
5238
5345
  * Decrement a statistic counter
@@ -5241,40 +5348,62 @@ class BaseStorageAdapter {
5241
5348
  * @param amount The amount to decrement by (default: 1)
5242
5349
  */
5243
5350
  async decrementStatistic(type, service, amount = 1) {
5244
- // Get current statistics or create default if not exists
5245
- let statistics = await this.getStatisticsData();
5351
+ // Get current statistics from cache or storage
5352
+ let statistics = this.statisticsCache;
5246
5353
  if (!statistics) {
5247
- statistics = this.createDefaultStatistics();
5354
+ statistics = await this.getStatisticsData();
5355
+ if (!statistics) {
5356
+ statistics = this.createDefaultStatistics();
5357
+ }
5358
+ // Update the cache
5359
+ this.statisticsCache = {
5360
+ nounCount: { ...statistics.nounCount },
5361
+ verbCount: { ...statistics.verbCount },
5362
+ metadataCount: { ...statistics.metadataCount },
5363
+ hnswIndexSize: statistics.hnswIndexSize,
5364
+ lastUpdated: statistics.lastUpdated
5365
+ };
5248
5366
  }
5249
5367
  // Decrement the appropriate counter
5250
5368
  const counterMap = {
5251
- noun: statistics.nounCount,
5252
- verb: statistics.verbCount,
5253
- metadata: statistics.metadataCount
5369
+ noun: this.statisticsCache.nounCount,
5370
+ verb: this.statisticsCache.verbCount,
5371
+ metadata: this.statisticsCache.metadataCount
5254
5372
  };
5255
5373
  const counter = counterMap[type];
5256
5374
  counter[service] = Math.max(0, (counter[service] || 0) - amount);
5257
5375
  // Update timestamp
5258
- statistics.lastUpdated = new Date().toISOString();
5259
- // Save updated statistics
5260
- await this.saveStatisticsData(statistics);
5376
+ this.statisticsCache.lastUpdated = new Date().toISOString();
5377
+ // Schedule a batch update instead of saving immediately
5378
+ this.scheduleBatchUpdate();
5261
5379
  }
5262
5380
  /**
5263
5381
  * Update the HNSW index size statistic
5264
5382
  * @param size The new size of the HNSW index
5265
5383
  */
5266
5384
  async updateHnswIndexSize(size) {
5267
- // Get current statistics or create default if not exists
5268
- let statistics = await this.getStatisticsData();
5385
+ // Get current statistics from cache or storage
5386
+ let statistics = this.statisticsCache;
5269
5387
  if (!statistics) {
5270
- statistics = this.createDefaultStatistics();
5388
+ statistics = await this.getStatisticsData();
5389
+ if (!statistics) {
5390
+ statistics = this.createDefaultStatistics();
5391
+ }
5392
+ // Update the cache
5393
+ this.statisticsCache = {
5394
+ nounCount: { ...statistics.nounCount },
5395
+ verbCount: { ...statistics.verbCount },
5396
+ metadataCount: { ...statistics.metadataCount },
5397
+ hnswIndexSize: statistics.hnswIndexSize,
5398
+ lastUpdated: statistics.lastUpdated
5399
+ };
5271
5400
  }
5272
5401
  // Update HNSW index size
5273
- statistics.hnswIndexSize = size;
5402
+ this.statisticsCache.hnswIndexSize = size;
5274
5403
  // Update timestamp
5275
- statistics.lastUpdated = new Date().toISOString();
5276
- // Save updated statistics
5277
- await this.saveStatisticsData(statistics);
5404
+ this.statisticsCache.lastUpdated = new Date().toISOString();
5405
+ // Schedule a batch update instead of saving immediately
5406
+ this.scheduleBatchUpdate();
5278
5407
  }
5279
5408
  /**
5280
5409
  * Create default statistics data
@@ -5323,21 +5452,21 @@ class BaseStorage extends BaseStorageAdapter {
5323
5452
  */
5324
5453
  async saveNoun(noun) {
5325
5454
  await this.ensureInitialized();
5326
- return this.saveNode(noun);
5455
+ return this.saveNoun_internal(noun);
5327
5456
  }
5328
5457
  /**
5329
5458
  * Get a noun from storage
5330
5459
  */
5331
5460
  async getNoun(id) {
5332
5461
  await this.ensureInitialized();
5333
- return this.getNode(id);
5462
+ return this.getNoun_internal(id);
5334
5463
  }
5335
5464
  /**
5336
5465
  * Get all nouns from storage
5337
5466
  */
5338
5467
  async getAllNouns() {
5339
5468
  await this.ensureInitialized();
5340
- return this.getAllNodes();
5469
+ return this.getAllNouns_internal();
5341
5470
  }
5342
5471
  /**
5343
5472
  * Get nouns by noun type
@@ -5346,63 +5475,63 @@ class BaseStorage extends BaseStorageAdapter {
5346
5475
  */
5347
5476
  async getNounsByNounType(nounType) {
5348
5477
  await this.ensureInitialized();
5349
- return this.getNodesByNounType(nounType);
5478
+ return this.getNounsByNounType_internal(nounType);
5350
5479
  }
5351
5480
  /**
5352
5481
  * Delete a noun from storage
5353
5482
  */
5354
5483
  async deleteNoun(id) {
5355
5484
  await this.ensureInitialized();
5356
- return this.deleteNode(id);
5485
+ return this.deleteNoun_internal(id);
5357
5486
  }
5358
5487
  /**
5359
5488
  * Save a verb to storage
5360
5489
  */
5361
5490
  async saveVerb(verb) {
5362
5491
  await this.ensureInitialized();
5363
- return this.saveEdge(verb);
5492
+ return this.saveVerb_internal(verb);
5364
5493
  }
5365
5494
  /**
5366
5495
  * Get a verb from storage
5367
5496
  */
5368
5497
  async getVerb(id) {
5369
5498
  await this.ensureInitialized();
5370
- return this.getEdge(id);
5499
+ return this.getVerb_internal(id);
5371
5500
  }
5372
5501
  /**
5373
5502
  * Get all verbs from storage
5374
5503
  */
5375
5504
  async getAllVerbs() {
5376
5505
  await this.ensureInitialized();
5377
- return this.getAllEdges();
5506
+ return this.getAllVerbs_internal();
5378
5507
  }
5379
5508
  /**
5380
5509
  * Get verbs by source
5381
5510
  */
5382
5511
  async getVerbsBySource(sourceId) {
5383
5512
  await this.ensureInitialized();
5384
- return this.getEdgesBySource(sourceId);
5513
+ return this.getVerbsBySource_internal(sourceId);
5385
5514
  }
5386
5515
  /**
5387
5516
  * Get verbs by target
5388
5517
  */
5389
5518
  async getVerbsByTarget(targetId) {
5390
5519
  await this.ensureInitialized();
5391
- return this.getEdgesByTarget(targetId);
5520
+ return this.getVerbsByTarget_internal(targetId);
5392
5521
  }
5393
5522
  /**
5394
5523
  * Get verbs by type
5395
5524
  */
5396
5525
  async getVerbsByType(type) {
5397
5526
  await this.ensureInitialized();
5398
- return this.getEdgesByType(type);
5527
+ return this.getVerbsByType_internal(type);
5399
5528
  }
5400
5529
  /**
5401
5530
  * Delete a verb from storage
5402
5531
  */
5403
5532
  async deleteVerb(id) {
5404
5533
  await this.ensureInitialized();
5405
- return this.deleteEdge(id);
5534
+ return this.deleteVerb_internal(id);
5406
5535
  }
5407
5536
  /**
5408
5537
  * Helper method to convert a Map to a plain object for serialization
@@ -5441,201 +5570,230 @@ class MemoryStorage extends BaseStorage {
5441
5570
  this.isInitialized = true;
5442
5571
  }
5443
5572
  /**
5444
- * Save a node to storage
5573
+ * Save a noun to storage
5445
5574
  */
5446
- async saveNode(node) {
5575
+ async saveNoun_internal(noun) {
5447
5576
  // Create a deep copy to avoid reference issues
5448
- const nodeCopy = {
5449
- id: node.id,
5450
- vector: [...node.vector],
5577
+ const nounCopy = {
5578
+ id: noun.id,
5579
+ vector: [...noun.vector],
5451
5580
  connections: new Map()
5452
5581
  };
5453
5582
  // Copy connections
5454
- for (const [level, connections] of node.connections.entries()) {
5455
- nodeCopy.connections.set(level, new Set(connections));
5583
+ for (const [level, connections] of noun.connections.entries()) {
5584
+ nounCopy.connections.set(level, new Set(connections));
5456
5585
  }
5457
- // Save the node directly in the nouns map
5458
- this.nouns.set(node.id, nodeCopy);
5586
+ // Save the noun directly in the nouns map
5587
+ this.nouns.set(noun.id, nounCopy);
5459
5588
  }
5460
5589
  /**
5461
- * Get a node from storage
5590
+ * Get a noun from storage
5462
5591
  */
5463
- async getNode(id) {
5464
- // Get the node directly from the nouns map
5465
- const node = this.nouns.get(id);
5592
+ async getNoun_internal(id) {
5593
+ // Get the noun directly from the nouns map
5594
+ const noun = this.nouns.get(id);
5466
5595
  // If not found, return null
5467
- if (!node) {
5596
+ if (!noun) {
5468
5597
  return null;
5469
5598
  }
5470
5599
  // Return a deep copy to avoid reference issues
5471
- const nodeCopy = {
5472
- id: node.id,
5473
- vector: [...node.vector],
5600
+ const nounCopy = {
5601
+ id: noun.id,
5602
+ vector: [...noun.vector],
5474
5603
  connections: new Map()
5475
5604
  };
5476
5605
  // Copy connections
5477
- for (const [level, connections] of node.connections.entries()) {
5478
- nodeCopy.connections.set(level, new Set(connections));
5606
+ for (const [level, connections] of noun.connections.entries()) {
5607
+ nounCopy.connections.set(level, new Set(connections));
5479
5608
  }
5480
- return nodeCopy;
5609
+ return nounCopy;
5481
5610
  }
5482
5611
  /**
5483
- * Get all nodes from storage
5612
+ * Get all nouns from storage
5484
5613
  */
5485
- async getAllNodes() {
5486
- const allNodes = [];
5487
- // Iterate through all nodes in the nouns map
5488
- for (const [nodeId, node] of this.nouns.entries()) {
5614
+ async getAllNouns_internal() {
5615
+ const allNouns = [];
5616
+ // Iterate through all nouns in the nouns map
5617
+ for (const [nounId, noun] of this.nouns.entries()) {
5489
5618
  // Return a deep copy to avoid reference issues
5490
- const nodeCopy = {
5491
- id: node.id,
5492
- vector: [...node.vector],
5619
+ const nounCopy = {
5620
+ id: noun.id,
5621
+ vector: [...noun.vector],
5493
5622
  connections: new Map()
5494
5623
  };
5495
5624
  // Copy connections
5496
- for (const [level, connections] of node.connections.entries()) {
5497
- nodeCopy.connections.set(level, new Set(connections));
5625
+ for (const [level, connections] of noun.connections.entries()) {
5626
+ nounCopy.connections.set(level, new Set(connections));
5498
5627
  }
5499
- allNodes.push(nodeCopy);
5628
+ allNouns.push(nounCopy);
5500
5629
  }
5501
- return allNodes;
5630
+ return allNouns;
5502
5631
  }
5503
5632
  /**
5504
- * Get nodes by noun type
5633
+ * Get nouns by noun type
5505
5634
  * @param nounType The noun type to filter by
5506
- * @returns Promise that resolves to an array of nodes of the specified noun type
5635
+ * @returns Promise that resolves to an array of nouns of the specified noun type
5507
5636
  */
5508
- async getNodesByNounType(nounType) {
5509
- const nodes = [];
5510
- // Iterate through all nodes and filter by noun type using metadata
5511
- for (const [nodeId, node] of this.nouns.entries()) {
5637
+ async getNounsByNounType_internal(nounType) {
5638
+ const nouns = [];
5639
+ // Iterate through all nouns and filter by noun type using metadata
5640
+ for (const [nounId, noun] of this.nouns.entries()) {
5512
5641
  // Get the metadata to check the noun type
5513
- const metadata = await this.getMetadata(nodeId);
5514
- // Include the node if its noun type matches the requested type
5642
+ const metadata = await this.getMetadata(nounId);
5643
+ // Include the noun if its noun type matches the requested type
5515
5644
  if (metadata && metadata.noun === nounType) {
5516
5645
  // Return a deep copy to avoid reference issues
5517
- const nodeCopy = {
5518
- id: node.id,
5519
- vector: [...node.vector],
5646
+ const nounCopy = {
5647
+ id: noun.id,
5648
+ vector: [...noun.vector],
5520
5649
  connections: new Map()
5521
5650
  };
5522
5651
  // Copy connections
5523
- for (const [level, connections] of node.connections.entries()) {
5524
- nodeCopy.connections.set(level, new Set(connections));
5652
+ for (const [level, connections] of noun.connections.entries()) {
5653
+ nounCopy.connections.set(level, new Set(connections));
5525
5654
  }
5526
- nodes.push(nodeCopy);
5655
+ nouns.push(nounCopy);
5527
5656
  }
5528
5657
  }
5529
- return nodes;
5658
+ return nouns;
5530
5659
  }
5531
5660
  /**
5532
- * Delete a node from storage
5661
+ * Delete a noun from storage
5533
5662
  */
5534
- async deleteNode(id) {
5535
- // Delete the node directly from the nouns map
5663
+ async deleteNoun_internal(id) {
5536
5664
  this.nouns.delete(id);
5537
5665
  }
5538
5666
  /**
5539
- * Save an edge to storage
5667
+ * Save a verb to storage
5540
5668
  */
5541
- async saveEdge(edge) {
5669
+ async saveVerb_internal(verb) {
5542
5670
  // Create a deep copy to avoid reference issues
5543
- const edgeCopy = {
5544
- id: edge.id,
5545
- vector: [...edge.vector],
5671
+ const verbCopy = {
5672
+ id: verb.id,
5673
+ vector: [...verb.vector],
5546
5674
  connections: new Map(),
5547
- sourceId: edge.sourceId,
5548
- targetId: edge.targetId,
5549
- type: edge.type,
5550
- weight: edge.weight,
5551
- metadata: edge.metadata
5675
+ sourceId: verb.sourceId,
5676
+ targetId: verb.targetId,
5677
+ type: verb.type,
5678
+ weight: verb.weight,
5679
+ metadata: verb.metadata
5552
5680
  };
5553
5681
  // Copy connections
5554
- for (const [level, connections] of edge.connections.entries()) {
5555
- edgeCopy.connections.set(level, new Set(connections));
5682
+ for (const [level, connections] of verb.connections.entries()) {
5683
+ verbCopy.connections.set(level, new Set(connections));
5556
5684
  }
5557
- // Save the edge directly in the verbs map
5558
- this.verbs.set(edge.id, edgeCopy);
5685
+ // Save the verb directly in the verbs map
5686
+ this.verbs.set(verb.id, verbCopy);
5559
5687
  }
5560
5688
  /**
5561
- * Get an edge from storage
5689
+ * Get a verb from storage
5562
5690
  */
5563
- async getEdge(id) {
5564
- // Get the edge directly from the verbs map
5565
- const edge = this.verbs.get(id);
5691
+ async getVerb_internal(id) {
5692
+ // Get the verb directly from the verbs map
5693
+ const verb = this.verbs.get(id);
5566
5694
  // If not found, return null
5567
- if (!edge) {
5695
+ if (!verb) {
5568
5696
  return null;
5569
5697
  }
5698
+ // Create default timestamp if not present
5699
+ const defaultTimestamp = {
5700
+ seconds: Math.floor(Date.now() / 1000),
5701
+ nanoseconds: (Date.now() % 1000) * 1000000
5702
+ };
5703
+ // Create default createdBy if not present
5704
+ const defaultCreatedBy = {
5705
+ augmentation: 'unknown',
5706
+ version: '1.0'
5707
+ };
5570
5708
  // Return a deep copy to avoid reference issues
5571
- const edgeCopy = {
5572
- id: edge.id,
5573
- vector: [...edge.vector],
5709
+ const verbCopy = {
5710
+ id: verb.id,
5711
+ vector: [...verb.vector],
5574
5712
  connections: new Map(),
5575
- sourceId: edge.sourceId,
5576
- targetId: edge.targetId,
5577
- type: edge.type,
5578
- weight: edge.weight,
5579
- metadata: edge.metadata
5713
+ sourceId: (verb.sourceId || verb.source || ""),
5714
+ targetId: (verb.targetId || verb.target || ""),
5715
+ source: (verb.sourceId || verb.source || ""),
5716
+ target: (verb.targetId || verb.target || ""),
5717
+ verb: verb.type || verb.verb,
5718
+ weight: verb.weight,
5719
+ metadata: verb.metadata,
5720
+ createdAt: verb.createdAt || defaultTimestamp,
5721
+ updatedAt: verb.updatedAt || defaultTimestamp,
5722
+ createdBy: verb.createdBy || defaultCreatedBy
5580
5723
  };
5581
5724
  // Copy connections
5582
- for (const [level, connections] of edge.connections.entries()) {
5583
- edgeCopy.connections.set(level, new Set(connections));
5725
+ for (const [level, connections] of verb.connections.entries()) {
5726
+ verbCopy.connections.set(level, new Set(connections));
5584
5727
  }
5585
- return edgeCopy;
5728
+ return verbCopy;
5586
5729
  }
5587
5730
  /**
5588
- * Get all edges from storage
5731
+ * Get all verbs from storage
5589
5732
  */
5590
- async getAllEdges() {
5591
- const allEdges = [];
5592
- // Iterate through all edges in the verbs map
5593
- for (const [edgeId, edge] of this.verbs.entries()) {
5733
+ async getAllVerbs_internal() {
5734
+ const allVerbs = [];
5735
+ // Iterate through all verbs in the verbs map
5736
+ for (const [verbId, verb] of this.verbs.entries()) {
5737
+ // Create default timestamp if not present
5738
+ const defaultTimestamp = {
5739
+ seconds: Math.floor(Date.now() / 1000),
5740
+ nanoseconds: (Date.now() % 1000) * 1000000
5741
+ };
5742
+ // Create default createdBy if not present
5743
+ const defaultCreatedBy = {
5744
+ augmentation: 'unknown',
5745
+ version: '1.0'
5746
+ };
5594
5747
  // Return a deep copy to avoid reference issues
5595
- const edgeCopy = {
5596
- id: edge.id,
5597
- vector: [...edge.vector],
5748
+ const verbCopy = {
5749
+ id: verb.id,
5750
+ vector: [...verb.vector],
5598
5751
  connections: new Map(),
5599
- sourceId: edge.sourceId,
5600
- targetId: edge.targetId,
5601
- type: edge.type,
5602
- weight: edge.weight,
5603
- metadata: edge.metadata
5752
+ sourceId: (verb.sourceId || verb.source || ""),
5753
+ targetId: (verb.targetId || verb.target || ""),
5754
+ source: (verb.sourceId || verb.source || ""),
5755
+ target: (verb.targetId || verb.target || ""),
5756
+ verb: verb.type || verb.verb,
5757
+ weight: verb.weight,
5758
+ metadata: verb.metadata,
5759
+ createdAt: verb.createdAt || defaultTimestamp,
5760
+ updatedAt: verb.updatedAt || defaultTimestamp,
5761
+ createdBy: verb.createdBy || defaultCreatedBy
5604
5762
  };
5605
5763
  // Copy connections
5606
- for (const [level, connections] of edge.connections.entries()) {
5607
- edgeCopy.connections.set(level, new Set(connections));
5764
+ for (const [level, connections] of verb.connections.entries()) {
5765
+ verbCopy.connections.set(level, new Set(connections));
5608
5766
  }
5609
- allEdges.push(edgeCopy);
5767
+ allVerbs.push(verbCopy);
5610
5768
  }
5611
- return allEdges;
5769
+ return allVerbs;
5612
5770
  }
5613
5771
  /**
5614
- * Get edges by source
5772
+ * Get verbs by source
5615
5773
  */
5616
- async getEdgesBySource(sourceId) {
5617
- const edges = await this.getAllEdges();
5618
- return edges.filter((edge) => edge.sourceId === sourceId);
5774
+ async getVerbsBySource_internal(sourceId) {
5775
+ const allVerbs = await this.getAllVerbs_internal();
5776
+ return allVerbs.filter((verb) => (verb.sourceId || verb.source) === sourceId);
5619
5777
  }
5620
5778
  /**
5621
- * Get edges by target
5779
+ * Get verbs by target
5622
5780
  */
5623
- async getEdgesByTarget(targetId) {
5624
- const edges = await this.getAllEdges();
5625
- return edges.filter((edge) => edge.targetId === targetId);
5781
+ async getVerbsByTarget_internal(targetId) {
5782
+ const allVerbs = await this.getAllVerbs_internal();
5783
+ return allVerbs.filter((verb) => (verb.targetId || verb.target) === targetId);
5626
5784
  }
5627
5785
  /**
5628
- * Get edges by type
5786
+ * Get verbs by type
5629
5787
  */
5630
- async getEdgesByType(type) {
5631
- const edges = await this.getAllEdges();
5632
- return edges.filter((edge) => edge.type === type);
5788
+ async getVerbsByType_internal(type) {
5789
+ const allVerbs = await this.getAllVerbs_internal();
5790
+ return allVerbs.filter((verb) => (verb.type || verb.verb) === type);
5633
5791
  }
5634
5792
  /**
5635
- * Delete an edge from storage
5793
+ * Delete a verb from storage
5636
5794
  */
5637
- async deleteEdge(id) {
5638
- // Delete the edge directly from the verbs map
5795
+ async deleteVerb_internal(id) {
5796
+ // Delete the verb directly from the verbs map
5639
5797
  this.verbs.delete(id);
5640
5798
  }
5641
5799
  /**
@@ -5682,6 +5840,7 @@ class MemoryStorage extends BaseStorage {
5682
5840
  * @param statistics The statistics data to save
5683
5841
  */
5684
5842
  async saveStatisticsData(statistics) {
5843
+ // For memory storage, we just need to store the statistics in memory
5685
5844
  // Create a deep copy to avoid reference issues
5686
5845
  this.statistics = {
5687
5846
  nounCount: { ...statistics.nounCount },
@@ -5690,6 +5849,8 @@ class MemoryStorage extends BaseStorage {
5690
5849
  hnswIndexSize: statistics.hnswIndexSize,
5691
5850
  lastUpdated: statistics.lastUpdated
5692
5851
  };
5852
+ // Since this is in-memory, there's no need for time-based partitioning
5853
+ // or legacy file handling
5693
5854
  }
5694
5855
  /**
5695
5856
  * Get statistics data from storage
@@ -5707,6 +5868,8 @@ class MemoryStorage extends BaseStorage {
5707
5868
  hnswIndexSize: this.statistics.hnswIndexSize,
5708
5869
  lastUpdated: this.statistics.lastUpdated
5709
5870
  };
5871
+ // Since this is in-memory, there's no need for fallback mechanisms
5872
+ // to check multiple storage locations
5710
5873
  }
5711
5874
  }
5712
5875
 
@@ -5833,46 +5996,46 @@ class OPFSStorage extends BaseStorage {
5833
5996
  }
5834
5997
  }
5835
5998
  /**
5836
- * Save a node to storage
5999
+ * Save a noun to storage
5837
6000
  */
5838
- async saveNode(node) {
6001
+ async saveNoun_internal(noun) {
5839
6002
  await this.ensureInitialized();
5840
6003
  try {
5841
6004
  // Convert connections Map to a serializable format
5842
- const serializableNode = {
5843
- ...node,
5844
- connections: this.mapToObject(node.connections, (set) => Array.from(set))
6005
+ const serializableNoun = {
6006
+ ...noun,
6007
+ connections: this.mapToObject(noun.connections, (set) => Array.from(set))
5845
6008
  };
5846
6009
  // Create or get the file for this noun
5847
- const fileHandle = await this.nounsDir.getFileHandle(node.id, {
6010
+ const fileHandle = await this.nounsDir.getFileHandle(noun.id, {
5848
6011
  create: true
5849
6012
  });
5850
6013
  // Write the noun data to the file
5851
6014
  const writable = await fileHandle.createWritable();
5852
- await writable.write(JSON.stringify(serializableNode));
6015
+ await writable.write(JSON.stringify(serializableNoun));
5853
6016
  await writable.close();
5854
6017
  }
5855
6018
  catch (error) {
5856
- console.error(`Failed to save node ${node.id}:`, error);
5857
- throw new Error(`Failed to save node ${node.id}: ${error}`);
6019
+ console.error(`Failed to save noun ${noun.id}:`, error);
6020
+ throw new Error(`Failed to save noun ${noun.id}: ${error}`);
5858
6021
  }
5859
6022
  }
5860
6023
  /**
5861
- * Get a node from storage
6024
+ * Get a noun from storage
5862
6025
  */
5863
- async getNode(id) {
6026
+ async getNoun_internal(id) {
5864
6027
  await this.ensureInitialized();
5865
6028
  try {
5866
- // Get the file handle for this node
6029
+ // Get the file handle for this noun
5867
6030
  const fileHandle = await this.nounsDir.getFileHandle(id);
5868
- // Read the node data from the file
6031
+ // Read the noun data from the file
5869
6032
  const file = await fileHandle.getFile();
5870
6033
  const text = await file.text();
5871
6034
  const data = JSON.parse(text);
5872
6035
  // Convert serialized connections back to Map<number, Set<string>>
5873
6036
  const connections = new Map();
5874
- for (const [level, nodeIds] of Object.entries(data.connections)) {
5875
- connections.set(Number(level), new Set(nodeIds));
6037
+ for (const [level, nounIds] of Object.entries(data.connections)) {
6038
+ connections.set(Number(level), new Set(nounIds));
5876
6039
  }
5877
6040
  return {
5878
6041
  id: data.id,
@@ -5881,38 +6044,38 @@ class OPFSStorage extends BaseStorage {
5881
6044
  };
5882
6045
  }
5883
6046
  catch (error) {
5884
- // Node not found or other error
6047
+ // Noun not found or other error
5885
6048
  return null;
5886
6049
  }
5887
6050
  }
5888
6051
  /**
5889
- * Get all nodes from storage
6052
+ * Get all nouns from storage
5890
6053
  */
5891
- async getAllNodes() {
6054
+ async getAllNouns_internal() {
5892
6055
  await this.ensureInitialized();
5893
- const allNodes = [];
6056
+ const allNouns = [];
5894
6057
  try {
5895
6058
  // Iterate through all files in the nouns directory
5896
6059
  for await (const [name, handle] of this.nounsDir.entries()) {
5897
6060
  if (handle.kind === 'file') {
5898
6061
  try {
5899
- // Read the node data from the file
6062
+ // Read the noun data from the file
5900
6063
  const file = await safeGetFile(handle);
5901
6064
  const text = await file.text();
5902
6065
  const data = JSON.parse(text);
5903
6066
  // Convert serialized connections back to Map<number, Set<string>>
5904
6067
  const connections = new Map();
5905
- for (const [level, nodeIds] of Object.entries(data.connections)) {
5906
- connections.set(Number(level), new Set(nodeIds));
6068
+ for (const [level, nounIds] of Object.entries(data.connections)) {
6069
+ connections.set(Number(level), new Set(nounIds));
5907
6070
  }
5908
- allNodes.push({
6071
+ allNouns.push({
5909
6072
  id: data.id,
5910
6073
  vector: data.vector,
5911
6074
  connections
5912
6075
  });
5913
6076
  }
5914
6077
  catch (error) {
5915
- console.error(`Error reading node file ${name}:`, error);
6078
+ console.error(`Error reading noun file ${name}:`, error);
5916
6079
  }
5917
6080
  }
5918
6081
  }
@@ -5920,7 +6083,15 @@ class OPFSStorage extends BaseStorage {
5920
6083
  catch (error) {
5921
6084
  console.error('Error reading nouns directory:', error);
5922
6085
  }
5923
- return allNodes;
6086
+ return allNouns;
6087
+ }
6088
+ /**
6089
+ * Get nouns by noun type (internal implementation)
6090
+ * @param nounType The noun type to filter by
6091
+ * @returns Promise that resolves to an array of nouns of the specified noun type
6092
+ */
6093
+ async getNounsByNounType_internal(nounType) {
6094
+ return this.getNodesByNounType(nounType);
5924
6095
  }
5925
6096
  /**
5926
6097
  * Get nodes by noun type
@@ -5966,6 +6137,12 @@ class OPFSStorage extends BaseStorage {
5966
6137
  }
5967
6138
  return nodes;
5968
6139
  }
6140
+ /**
6141
+ * Delete a noun from storage (internal implementation)
6142
+ */
6143
+ async deleteNoun_internal(id) {
6144
+ return this.deleteNode(id);
6145
+ }
5969
6146
  /**
5970
6147
  * Delete a node from storage
5971
6148
  */
@@ -5982,6 +6159,12 @@ class OPFSStorage extends BaseStorage {
5982
6159
  }
5983
6160
  }
5984
6161
  }
6162
+ /**
6163
+ * Save a verb to storage (internal implementation)
6164
+ */
6165
+ async saveVerb_internal(verb) {
6166
+ return this.saveEdge(verb);
6167
+ }
5985
6168
  /**
5986
6169
  * Save an edge to storage
5987
6170
  */
@@ -6007,6 +6190,12 @@ class OPFSStorage extends BaseStorage {
6007
6190
  throw new Error(`Failed to save edge ${edge.id}: ${error}`);
6008
6191
  }
6009
6192
  }
6193
+ /**
6194
+ * Get a verb from storage (internal implementation)
6195
+ */
6196
+ async getVerb_internal(id) {
6197
+ return this.getEdge(id);
6198
+ }
6010
6199
  /**
6011
6200
  * Get an edge from storage
6012
6201
  */
@@ -6024,15 +6213,30 @@ class OPFSStorage extends BaseStorage {
6024
6213
  for (const [level, nodeIds] of Object.entries(data.connections)) {
6025
6214
  connections.set(Number(level), new Set(nodeIds));
6026
6215
  }
6216
+ // Create default timestamp if not present
6217
+ const defaultTimestamp = {
6218
+ seconds: Math.floor(Date.now() / 1000),
6219
+ nanoseconds: (Date.now() % 1000) * 1000000
6220
+ };
6221
+ // Create default createdBy if not present
6222
+ const defaultCreatedBy = {
6223
+ augmentation: 'unknown',
6224
+ version: '1.0'
6225
+ };
6027
6226
  return {
6028
6227
  id: data.id,
6029
6228
  vector: data.vector,
6030
6229
  connections,
6031
- sourceId: data.sourceId,
6032
- targetId: data.targetId,
6033
- type: data.type,
6230
+ sourceId: data.sourceId || data.source,
6231
+ targetId: data.targetId || data.target,
6232
+ source: data.sourceId || data.source,
6233
+ target: data.targetId || data.target,
6234
+ verb: data.type || data.verb,
6034
6235
  weight: data.weight,
6035
- metadata: data.metadata
6236
+ metadata: data.metadata,
6237
+ createdAt: data.createdAt || defaultTimestamp,
6238
+ updatedAt: data.updatedAt || defaultTimestamp,
6239
+ createdBy: data.createdBy || defaultCreatedBy
6036
6240
  };
6037
6241
  }
6038
6242
  catch (error) {
@@ -6040,6 +6244,12 @@ class OPFSStorage extends BaseStorage {
6040
6244
  return null;
6041
6245
  }
6042
6246
  }
6247
+ /**
6248
+ * Get all verbs from storage (internal implementation)
6249
+ */
6250
+ async getAllVerbs_internal() {
6251
+ return this.getAllEdges();
6252
+ }
6043
6253
  /**
6044
6254
  * Get all edges from storage
6045
6255
  */
@@ -6060,15 +6270,30 @@ class OPFSStorage extends BaseStorage {
6060
6270
  for (const [level, nodeIds] of Object.entries(data.connections)) {
6061
6271
  connections.set(Number(level), new Set(nodeIds));
6062
6272
  }
6273
+ // Create default timestamp if not present
6274
+ const defaultTimestamp = {
6275
+ seconds: Math.floor(Date.now() / 1000),
6276
+ nanoseconds: (Date.now() % 1000) * 1000000
6277
+ };
6278
+ // Create default createdBy if not present
6279
+ const defaultCreatedBy = {
6280
+ augmentation: 'unknown',
6281
+ version: '1.0'
6282
+ };
6063
6283
  allEdges.push({
6064
6284
  id: data.id,
6065
6285
  vector: data.vector,
6066
6286
  connections,
6067
- sourceId: data.sourceId,
6068
- targetId: data.targetId,
6069
- type: data.type,
6287
+ sourceId: data.sourceId || data.source,
6288
+ targetId: data.targetId || data.target,
6289
+ source: data.sourceId || data.source,
6290
+ target: data.targetId || data.target,
6291
+ verb: data.type || data.verb,
6070
6292
  weight: data.weight,
6071
- metadata: data.metadata
6293
+ metadata: data.metadata,
6294
+ createdAt: data.createdAt || defaultTimestamp,
6295
+ updatedAt: data.updatedAt || defaultTimestamp,
6296
+ createdBy: data.createdBy || defaultCreatedBy
6072
6297
  });
6073
6298
  }
6074
6299
  catch (error) {
@@ -6082,26 +6307,50 @@ class OPFSStorage extends BaseStorage {
6082
6307
  }
6083
6308
  return allEdges;
6084
6309
  }
6310
+ /**
6311
+ * Get verbs by source (internal implementation)
6312
+ */
6313
+ async getVerbsBySource_internal(sourceId) {
6314
+ return this.getEdgesBySource(sourceId);
6315
+ }
6085
6316
  /**
6086
6317
  * Get edges by source
6087
6318
  */
6088
6319
  async getEdgesBySource(sourceId) {
6089
6320
  const edges = await this.getAllEdges();
6090
- return edges.filter((edge) => edge.sourceId === sourceId);
6321
+ return edges.filter((edge) => (edge.sourceId || edge.source) === sourceId);
6322
+ }
6323
+ /**
6324
+ * Get verbs by target (internal implementation)
6325
+ */
6326
+ async getVerbsByTarget_internal(targetId) {
6327
+ return this.getEdgesByTarget(targetId);
6091
6328
  }
6092
6329
  /**
6093
6330
  * Get edges by target
6094
6331
  */
6095
6332
  async getEdgesByTarget(targetId) {
6096
6333
  const edges = await this.getAllEdges();
6097
- return edges.filter((edge) => edge.targetId === targetId);
6334
+ return edges.filter((edge) => (edge.targetId || edge.target) === targetId);
6335
+ }
6336
+ /**
6337
+ * Get verbs by type (internal implementation)
6338
+ */
6339
+ async getVerbsByType_internal(type) {
6340
+ return this.getEdgesByType(type);
6098
6341
  }
6099
6342
  /**
6100
6343
  * Get edges by type
6101
6344
  */
6102
6345
  async getEdgesByType(type) {
6103
6346
  const edges = await this.getAllEdges();
6104
- return edges.filter((edge) => edge.type === type);
6347
+ return edges.filter((edge) => (edge.type || edge.verb) === type);
6348
+ }
6349
+ /**
6350
+ * Delete a verb from storage (internal implementation)
6351
+ */
6352
+ async deleteVerb_internal(id) {
6353
+ return this.deleteEdge(id);
6105
6354
  }
6106
6355
  /**
6107
6356
  * Delete an edge from storage
@@ -6315,6 +6564,31 @@ class OPFSStorage extends BaseStorage {
6315
6564
  };
6316
6565
  }
6317
6566
  }
6567
+ /**
6568
+ * Get the statistics key for a specific date
6569
+ * @param date The date to get the key for
6570
+ * @returns The statistics key for the specified date
6571
+ */
6572
+ getStatisticsKeyForDate(date) {
6573
+ const year = date.getUTCFullYear();
6574
+ const month = String(date.getUTCMonth() + 1).padStart(2, '0');
6575
+ const day = String(date.getUTCDate()).padStart(2, '0');
6576
+ return `statistics_${year}${month}${day}.json`;
6577
+ }
6578
+ /**
6579
+ * Get the current statistics key
6580
+ * @returns The current statistics key
6581
+ */
6582
+ getCurrentStatisticsKey() {
6583
+ return this.getStatisticsKeyForDate(new Date());
6584
+ }
6585
+ /**
6586
+ * Get the legacy statistics key (for backward compatibility)
6587
+ * @returns The legacy statistics key
6588
+ */
6589
+ getLegacyStatisticsKey() {
6590
+ return 'statistics.json';
6591
+ }
6318
6592
  /**
6319
6593
  * Save statistics data to storage
6320
6594
  * @param statistics The statistics data to save
@@ -6335,8 +6609,10 @@ class OPFSStorage extends BaseStorage {
6335
6609
  if (!this.indexDir) {
6336
6610
  throw new Error('Index directory not initialized');
6337
6611
  }
6612
+ // Get the current statistics key
6613
+ const currentKey = this.getCurrentStatisticsKey();
6338
6614
  // Create a file for the statistics data
6339
- const fileHandle = await this.indexDir.getFileHandle('statistics.json', {
6615
+ const fileHandle = await this.indexDir.getFileHandle(currentKey, {
6340
6616
  create: true
6341
6617
  });
6342
6618
  // Create a writable stream
@@ -6345,6 +6621,16 @@ class OPFSStorage extends BaseStorage {
6345
6621
  await writable.write(JSON.stringify(this.statistics, null, 2));
6346
6622
  // Close the stream
6347
6623
  await writable.close();
6624
+ // Also update the legacy key for backward compatibility, but less frequently
6625
+ if (Math.random() < 0.1) {
6626
+ const legacyKey = this.getLegacyStatisticsKey();
6627
+ const legacyFileHandle = await this.indexDir.getFileHandle(legacyKey, {
6628
+ create: true
6629
+ });
6630
+ const legacyWritable = await legacyFileHandle.createWritable();
6631
+ await legacyWritable.write(JSON.stringify(this.statistics, null, 2));
6632
+ await legacyWritable.close();
6633
+ }
6348
6634
  }
6349
6635
  catch (error) {
6350
6636
  console.error('Failed to save statistics data:', error);
@@ -6372,17 +6658,15 @@ class OPFSStorage extends BaseStorage {
6372
6658
  if (!this.indexDir) {
6373
6659
  throw new Error('Index directory not initialized');
6374
6660
  }
6661
+ // First try to get statistics from today's file
6662
+ const currentKey = this.getCurrentStatisticsKey();
6375
6663
  try {
6376
- // Try to get the statistics file
6377
- const fileHandle = await this.indexDir.getFileHandle('statistics.json', {
6664
+ const fileHandle = await this.indexDir.getFileHandle(currentKey, {
6378
6665
  create: false
6379
6666
  });
6380
- // Get the file data
6381
6667
  const file = await fileHandle.getFile();
6382
6668
  const text = await file.text();
6383
- // Parse the statistics data
6384
6669
  this.statistics = JSON.parse(text);
6385
- // Return a deep copy
6386
6670
  if (this.statistics) {
6387
6671
  return {
6388
6672
  nounCount: { ...this.statistics.nounCount },
@@ -6392,13 +6676,57 @@ class OPFSStorage extends BaseStorage {
6392
6676
  lastUpdated: this.statistics.lastUpdated
6393
6677
  };
6394
6678
  }
6395
- // If statistics is null, return default statistics
6396
- return this.createDefaultStatistics();
6397
6679
  }
6398
6680
  catch (error) {
6399
- // If the file doesn't exist, return null
6400
- return null;
6681
+ // If today's file doesn't exist, try yesterday's file
6682
+ const yesterday = new Date();
6683
+ yesterday.setDate(yesterday.getDate() - 1);
6684
+ const yesterdayKey = this.getStatisticsKeyForDate(yesterday);
6685
+ try {
6686
+ const fileHandle = await this.indexDir.getFileHandle(yesterdayKey, {
6687
+ create: false
6688
+ });
6689
+ const file = await fileHandle.getFile();
6690
+ const text = await file.text();
6691
+ this.statistics = JSON.parse(text);
6692
+ if (this.statistics) {
6693
+ return {
6694
+ nounCount: { ...this.statistics.nounCount },
6695
+ verbCount: { ...this.statistics.verbCount },
6696
+ metadataCount: { ...this.statistics.metadataCount },
6697
+ hnswIndexSize: this.statistics.hnswIndexSize,
6698
+ lastUpdated: this.statistics.lastUpdated
6699
+ };
6700
+ }
6701
+ }
6702
+ catch (error) {
6703
+ // If yesterday's file doesn't exist, try the legacy file
6704
+ const legacyKey = this.getLegacyStatisticsKey();
6705
+ try {
6706
+ const fileHandle = await this.indexDir.getFileHandle(legacyKey, {
6707
+ create: false
6708
+ });
6709
+ const file = await fileHandle.getFile();
6710
+ const text = await file.text();
6711
+ this.statistics = JSON.parse(text);
6712
+ if (this.statistics) {
6713
+ return {
6714
+ nounCount: { ...this.statistics.nounCount },
6715
+ verbCount: { ...this.statistics.verbCount },
6716
+ metadataCount: { ...this.statistics.metadataCount },
6717
+ hnswIndexSize: this.statistics.hnswIndexSize,
6718
+ lastUpdated: this.statistics.lastUpdated
6719
+ };
6720
+ }
6721
+ }
6722
+ catch (error) {
6723
+ // If the legacy file doesn't exist either, return null
6724
+ return null;
6725
+ }
6726
+ }
6401
6727
  }
6728
+ // If we get here and statistics is null, return default statistics
6729
+ return this.statistics ? this.statistics : null;
6402
6730
  }
6403
6731
  catch (error) {
6404
6732
  console.error('Failed to get statistics data:', error);
@@ -6490,66 +6818,66 @@ class FileSystemStorage extends BaseStorage {
6490
6818
  }
6491
6819
  }
6492
6820
  /**
6493
- * Save a node to storage
6821
+ * Save a noun to storage
6494
6822
  */
6495
- async saveNode(node) {
6823
+ async saveNoun_internal(noun) {
6496
6824
  await this.ensureInitialized();
6497
6825
  // Convert connections Map to a serializable format
6498
- const serializableNode = {
6499
- ...node,
6500
- connections: this.mapToObject(node.connections, (set) => Array.from(set))
6826
+ const serializableNoun = {
6827
+ ...noun,
6828
+ connections: this.mapToObject(noun.connections, (set) => Array.from(set))
6501
6829
  };
6502
- const filePath = path.join(this.nounsDir, `${node.id}.json`);
6503
- await fs.promises.writeFile(filePath, JSON.stringify(serializableNode, null, 2));
6830
+ const filePath = path.join(this.nounsDir, `${noun.id}.json`);
6831
+ await fs.promises.writeFile(filePath, JSON.stringify(serializableNoun, null, 2));
6504
6832
  }
6505
6833
  /**
6506
- * Get a node from storage
6834
+ * Get a noun from storage
6507
6835
  */
6508
- async getNode(id) {
6836
+ async getNoun_internal(id) {
6509
6837
  await this.ensureInitialized();
6510
6838
  const filePath = path.join(this.nounsDir, `${id}.json`);
6511
6839
  try {
6512
6840
  const data = await fs.promises.readFile(filePath, 'utf-8');
6513
- const parsedNode = JSON.parse(data);
6841
+ const parsedNoun = JSON.parse(data);
6514
6842
  // Convert serialized connections back to Map<number, Set<string>>
6515
6843
  const connections = new Map();
6516
- for (const [level, nodeIds] of Object.entries(parsedNode.connections)) {
6517
- connections.set(Number(level), new Set(nodeIds));
6844
+ for (const [level, nounIds] of Object.entries(parsedNoun.connections)) {
6845
+ connections.set(Number(level), new Set(nounIds));
6518
6846
  }
6519
6847
  return {
6520
- id: parsedNode.id,
6521
- vector: parsedNode.vector,
6848
+ id: parsedNoun.id,
6849
+ vector: parsedNoun.vector,
6522
6850
  connections
6523
6851
  };
6524
6852
  }
6525
6853
  catch (error) {
6526
6854
  if (error.code !== 'ENOENT') {
6527
- console.error(`Error reading node ${id}:`, error);
6855
+ console.error(`Error reading noun ${id}:`, error);
6528
6856
  }
6529
6857
  return null;
6530
6858
  }
6531
6859
  }
6532
6860
  /**
6533
- * Get all nodes from storage
6861
+ * Get all nouns from storage
6534
6862
  */
6535
- async getAllNodes() {
6863
+ async getAllNouns_internal() {
6536
6864
  await this.ensureInitialized();
6537
- const allNodes = [];
6865
+ const allNouns = [];
6538
6866
  try {
6539
6867
  const files = await fs.promises.readdir(this.nounsDir);
6540
6868
  for (const file of files) {
6541
6869
  if (file.endsWith('.json')) {
6542
6870
  const filePath = path.join(this.nounsDir, file);
6543
6871
  const data = await fs.promises.readFile(filePath, 'utf-8');
6544
- const parsedNode = JSON.parse(data);
6872
+ const parsedNoun = JSON.parse(data);
6545
6873
  // Convert serialized connections back to Map<number, Set<string>>
6546
6874
  const connections = new Map();
6547
- for (const [level, nodeIds] of Object.entries(parsedNode.connections)) {
6548
- connections.set(Number(level), new Set(nodeIds));
6875
+ for (const [level, nounIds] of Object.entries(parsedNoun.connections)) {
6876
+ connections.set(Number(level), new Set(nounIds));
6549
6877
  }
6550
- allNodes.push({
6551
- id: parsedNode.id,
6552
- vector: parsedNode.vector,
6878
+ allNouns.push({
6879
+ id: parsedNoun.id,
6880
+ vector: parsedNoun.vector,
6553
6881
  connections
6554
6882
  });
6555
6883
  }
@@ -6560,14 +6888,14 @@ class FileSystemStorage extends BaseStorage {
6560
6888
  console.error(`Error reading directory ${this.nounsDir}:`, error);
6561
6889
  }
6562
6890
  }
6563
- return allNodes;
6891
+ return allNouns;
6564
6892
  }
6565
6893
  /**
6566
- * Get nodes by noun type
6894
+ * Get nouns by noun type
6567
6895
  * @param nounType The noun type to filter by
6568
- * @returns Promise that resolves to an array of nodes of the specified noun type
6896
+ * @returns Promise that resolves to an array of nouns of the specified noun type
6569
6897
  */
6570
- async getNodesByNounType(nounType) {
6898
+ async getNounsByNounType_internal(nounType) {
6571
6899
  await this.ensureInitialized();
6572
6900
  const nouns = [];
6573
6901
  try {
@@ -6576,19 +6904,19 @@ class FileSystemStorage extends BaseStorage {
6576
6904
  if (file.endsWith('.json')) {
6577
6905
  const filePath = path.join(this.nounsDir, file);
6578
6906
  const data = await fs.promises.readFile(filePath, 'utf-8');
6579
- const parsedNode = JSON.parse(data);
6907
+ const parsedNoun = JSON.parse(data);
6580
6908
  // Filter by noun type using metadata
6581
- const nodeId = parsedNode.id;
6582
- const metadata = await this.getMetadata(nodeId);
6909
+ const nounId = parsedNoun.id;
6910
+ const metadata = await this.getMetadata(nounId);
6583
6911
  if (metadata && metadata.noun === nounType) {
6584
6912
  // Convert serialized connections back to Map<number, Set<string>>
6585
6913
  const connections = new Map();
6586
- for (const [level, nodeIds] of Object.entries(parsedNode.connections)) {
6587
- connections.set(Number(level), new Set(nodeIds));
6914
+ for (const [level, nounIds] of Object.entries(parsedNoun.connections)) {
6915
+ connections.set(Number(level), new Set(nounIds));
6588
6916
  }
6589
6917
  nouns.push({
6590
- id: parsedNode.id,
6591
- vector: parsedNode.vector,
6918
+ id: parsedNoun.id,
6919
+ vector: parsedNoun.vector,
6592
6920
  connections
6593
6921
  });
6594
6922
  }
@@ -6603,9 +6931,9 @@ class FileSystemStorage extends BaseStorage {
6603
6931
  return nouns;
6604
6932
  }
6605
6933
  /**
6606
- * Delete a node from storage
6934
+ * Delete a noun from storage
6607
6935
  */
6608
- async deleteNode(id) {
6936
+ async deleteNoun_internal(id) {
6609
6937
  await this.ensureInitialized();
6610
6938
  const filePath = path.join(this.nounsDir, `${id}.json`);
6611
6939
  try {
@@ -6613,83 +6941,98 @@ class FileSystemStorage extends BaseStorage {
6613
6941
  }
6614
6942
  catch (error) {
6615
6943
  if (error.code !== 'ENOENT') {
6616
- console.error(`Error deleting node file ${filePath}:`, error);
6944
+ console.error(`Error deleting noun ${id}:`, error);
6617
6945
  throw error;
6618
6946
  }
6619
6947
  }
6620
6948
  }
6621
6949
  /**
6622
- * Save an edge to storage
6950
+ * Save a verb to storage
6623
6951
  */
6624
- async saveEdge(edge) {
6952
+ async saveVerb_internal(verb) {
6625
6953
  await this.ensureInitialized();
6626
6954
  // Convert connections Map to a serializable format
6627
- const serializableEdge = {
6628
- ...edge,
6629
- connections: this.mapToObject(edge.connections, (set) => Array.from(set))
6955
+ const serializableVerb = {
6956
+ ...verb,
6957
+ connections: this.mapToObject(verb.connections, (set) => Array.from(set))
6630
6958
  };
6631
- const filePath = path.join(this.verbsDir, `${edge.id}.json`);
6632
- await fs.promises.writeFile(filePath, JSON.stringify(serializableEdge, null, 2));
6959
+ const filePath = path.join(this.verbsDir, `${verb.id}.json`);
6960
+ await fs.promises.writeFile(filePath, JSON.stringify(serializableVerb, null, 2));
6633
6961
  }
6634
6962
  /**
6635
- * Get an edge from storage
6963
+ * Get a verb from storage
6636
6964
  */
6637
- async getEdge(id) {
6965
+ async getVerb_internal(id) {
6638
6966
  await this.ensureInitialized();
6639
6967
  const filePath = path.join(this.verbsDir, `${id}.json`);
6640
6968
  try {
6641
6969
  const data = await fs.promises.readFile(filePath, 'utf-8');
6642
- const parsedEdge = JSON.parse(data);
6970
+ const parsedVerb = JSON.parse(data);
6643
6971
  // Convert serialized connections back to Map<number, Set<string>>
6644
6972
  const connections = new Map();
6645
- for (const [level, nodeIds] of Object.entries(parsedEdge.connections)) {
6973
+ for (const [level, nodeIds] of Object.entries(parsedVerb.connections)) {
6646
6974
  connections.set(Number(level), new Set(nodeIds));
6647
6975
  }
6976
+ // Create default timestamp if not present
6977
+ const defaultTimestamp = {
6978
+ seconds: Math.floor(Date.now() / 1000),
6979
+ nanoseconds: (Date.now() % 1000) * 1000000
6980
+ };
6981
+ // Create default createdBy if not present
6982
+ const defaultCreatedBy = {
6983
+ augmentation: 'unknown',
6984
+ version: '1.0'
6985
+ };
6648
6986
  return {
6649
- id: parsedEdge.id,
6650
- vector: parsedEdge.vector,
6987
+ id: parsedVerb.id,
6988
+ vector: parsedVerb.vector,
6651
6989
  connections,
6652
- sourceId: parsedEdge.sourceId,
6653
- targetId: parsedEdge.targetId,
6654
- type: parsedEdge.type,
6655
- weight: parsedEdge.weight,
6656
- metadata: parsedEdge.metadata
6990
+ sourceId: parsedVerb.sourceId || parsedVerb.source,
6991
+ targetId: parsedVerb.targetId || parsedVerb.target,
6992
+ source: parsedVerb.sourceId || parsedVerb.source,
6993
+ target: parsedVerb.targetId || parsedVerb.target,
6994
+ verb: parsedVerb.type || parsedVerb.verb,
6995
+ weight: parsedVerb.weight,
6996
+ metadata: parsedVerb.metadata,
6997
+ createdAt: parsedVerb.createdAt || defaultTimestamp,
6998
+ updatedAt: parsedVerb.updatedAt || defaultTimestamp,
6999
+ createdBy: parsedVerb.createdBy || defaultCreatedBy
6657
7000
  };
6658
7001
  }
6659
7002
  catch (error) {
6660
7003
  if (error.code !== 'ENOENT') {
6661
- console.error(`Error reading edge ${id}:`, error);
7004
+ console.error(`Error reading verb ${id}:`, error);
6662
7005
  }
6663
7006
  return null;
6664
7007
  }
6665
7008
  }
6666
7009
  /**
6667
- * Get all edges from storage
7010
+ * Get all verbs from storage
6668
7011
  */
6669
- async getAllEdges() {
7012
+ async getAllVerbs_internal() {
6670
7013
  await this.ensureInitialized();
6671
- const allEdges = [];
7014
+ const allVerbs = [];
6672
7015
  try {
6673
7016
  const files = await fs.promises.readdir(this.verbsDir);
6674
7017
  for (const file of files) {
6675
7018
  if (file.endsWith('.json')) {
6676
7019
  const filePath = path.join(this.verbsDir, file);
6677
7020
  const data = await fs.promises.readFile(filePath, 'utf-8');
6678
- const parsedEdge = JSON.parse(data);
7021
+ const parsedVerb = JSON.parse(data);
6679
7022
  // Convert serialized connections back to Map<number, Set<string>>
6680
7023
  const connections = new Map();
6681
- for (const [level, nodeIds] of Object.entries(parsedEdge.connections)) {
7024
+ for (const [level, nodeIds] of Object.entries(parsedVerb.connections)) {
6682
7025
  connections.set(Number(level), new Set(nodeIds));
6683
7026
  }
6684
- allEdges.push({
6685
- id: parsedEdge.id,
6686
- vector: parsedEdge.vector,
7027
+ allVerbs.push({
7028
+ id: parsedVerb.id,
7029
+ vector: parsedVerb.vector,
6687
7030
  connections,
6688
- sourceId: parsedEdge.sourceId,
6689
- targetId: parsedEdge.targetId,
6690
- type: parsedEdge.type,
6691
- weight: parsedEdge.weight,
6692
- metadata: parsedEdge.metadata
7031
+ sourceId: parsedVerb.sourceId,
7032
+ targetId: parsedVerb.targetId,
7033
+ type: parsedVerb.type,
7034
+ weight: parsedVerb.weight,
7035
+ metadata: parsedVerb.metadata
6693
7036
  });
6694
7037
  }
6695
7038
  }
@@ -6699,33 +7042,33 @@ class FileSystemStorage extends BaseStorage {
6699
7042
  console.error(`Error reading directory ${this.verbsDir}:`, error);
6700
7043
  }
6701
7044
  }
6702
- return allEdges;
7045
+ return allVerbs;
6703
7046
  }
6704
7047
  /**
6705
- * Get edges by source
7048
+ * Get verbs by source
6706
7049
  */
6707
- async getEdgesBySource(sourceId) {
6708
- const edges = await this.getAllEdges();
6709
- return edges.filter((edge) => edge.sourceId === sourceId);
7050
+ async getVerbsBySource_internal(sourceId) {
7051
+ const verbs = await this.getAllVerbs_internal();
7052
+ return verbs.filter((verb) => (verb.sourceId || verb.source) === sourceId);
6710
7053
  }
6711
7054
  /**
6712
- * Get edges by target
7055
+ * Get verbs by target
6713
7056
  */
6714
- async getEdgesByTarget(targetId) {
6715
- const edges = await this.getAllEdges();
6716
- return edges.filter((edge) => edge.targetId === targetId);
7057
+ async getVerbsByTarget_internal(targetId) {
7058
+ const verbs = await this.getAllVerbs_internal();
7059
+ return verbs.filter((verb) => (verb.targetId || verb.target) === targetId);
6717
7060
  }
6718
7061
  /**
6719
- * Get edges by type
7062
+ * Get verbs by type
6720
7063
  */
6721
- async getEdgesByType(type) {
6722
- const edges = await this.getAllEdges();
6723
- return edges.filter((edge) => edge.type === type);
7064
+ async getVerbsByType_internal(type) {
7065
+ const verbs = await this.getAllVerbs_internal();
7066
+ return verbs.filter((verb) => (verb.type || verb.verb) === type);
6724
7067
  }
6725
7068
  /**
6726
- * Delete an edge from storage
7069
+ * Delete a verb from storage
6727
7070
  */
6728
- async deleteEdge(id) {
7071
+ async deleteVerb_internal(id) {
6729
7072
  await this.ensureInitialized();
6730
7073
  const filePath = path.join(this.verbsDir, `${id}.json`);
6731
7074
  try {
@@ -6733,7 +7076,7 @@ class FileSystemStorage extends BaseStorage {
6733
7076
  }
6734
7077
  catch (error) {
6735
7078
  if (error.code !== 'ENOENT') {
6736
- console.error(`Error deleting edge file ${filePath}:`, error);
7079
+ console.error(`Error deleting verb file ${filePath}:`, error);
6737
7080
  throw error;
6738
7081
  }
6739
7082
  }
@@ -6893,8 +7236,20 @@ class FileSystemStorage extends BaseStorage {
6893
7236
  async saveStatisticsData(statistics) {
6894
7237
  await this.ensureInitialized();
6895
7238
  try {
6896
- const filePath = path.join(this.indexDir, `${STATISTICS_KEY}.json`);
6897
- await fs.promises.writeFile(filePath, JSON.stringify(statistics, null, 2));
7239
+ // Get the current date for time-based partitioning
7240
+ const now = new Date();
7241
+ const year = now.getUTCFullYear();
7242
+ const month = String(now.getUTCMonth() + 1).padStart(2, '0');
7243
+ const day = String(now.getUTCDate()).padStart(2, '0');
7244
+ const dateStr = `${year}${month}${day}`;
7245
+ // Save to the current day's file
7246
+ const currentFilePath = path.join(this.indexDir, `${STATISTICS_KEY}_${dateStr}.json`);
7247
+ await fs.promises.writeFile(currentFilePath, JSON.stringify(statistics, null, 2));
7248
+ // Also update the legacy file for backward compatibility (less frequently)
7249
+ if (Math.random() < 0.1) {
7250
+ const legacyFilePath = path.join(this.indexDir, `${STATISTICS_KEY}.json`);
7251
+ await fs.promises.writeFile(legacyFilePath, JSON.stringify(statistics, null, 2));
7252
+ }
6898
7253
  }
6899
7254
  catch (error) {
6900
7255
  console.error('Failed to save statistics data:', error);
@@ -6908,15 +7263,54 @@ class FileSystemStorage extends BaseStorage {
6908
7263
  async getStatisticsData() {
6909
7264
  await this.ensureInitialized();
6910
7265
  try {
6911
- const filePath = path.join(this.indexDir, `${STATISTICS_KEY}.json`);
6912
- const data = await fs.promises.readFile(filePath, 'utf-8');
6913
- return JSON.parse(data);
7266
+ // Try to get statistics from today's file first
7267
+ const now = new Date();
7268
+ const year = now.getUTCFullYear();
7269
+ const month = String(now.getUTCMonth() + 1).padStart(2, '0');
7270
+ const day = String(now.getUTCDate()).padStart(2, '0');
7271
+ const dateStr = `${year}${month}${day}`;
7272
+ const currentFilePath = path.join(this.indexDir, `${STATISTICS_KEY}_${dateStr}.json`);
7273
+ try {
7274
+ const data = await fs.promises.readFile(currentFilePath, 'utf-8');
7275
+ return JSON.parse(data);
7276
+ }
7277
+ catch (currentError) {
7278
+ // If today's file doesn't exist, try yesterday's file
7279
+ if (currentError.code === 'ENOENT') {
7280
+ const yesterday = new Date();
7281
+ yesterday.setDate(yesterday.getDate() - 1);
7282
+ const yesterdayYear = yesterday.getUTCFullYear();
7283
+ const yesterdayMonth = String(yesterday.getUTCMonth() + 1).padStart(2, '0');
7284
+ const yesterdayDay = String(yesterday.getUTCDate()).padStart(2, '0');
7285
+ const yesterdayDateStr = `${yesterdayYear}${yesterdayMonth}${yesterdayDay}`;
7286
+ const yesterdayFilePath = path.join(this.indexDir, `${STATISTICS_KEY}_${yesterdayDateStr}.json`);
7287
+ try {
7288
+ const yesterdayData = await fs.promises.readFile(yesterdayFilePath, 'utf-8');
7289
+ return JSON.parse(yesterdayData);
7290
+ }
7291
+ catch (yesterdayError) {
7292
+ // If yesterday's file doesn't exist, try the legacy file
7293
+ if (yesterdayError.code === 'ENOENT') {
7294
+ const legacyFilePath = path.join(this.indexDir, `${STATISTICS_KEY}.json`);
7295
+ try {
7296
+ const legacyData = await fs.promises.readFile(legacyFilePath, 'utf-8');
7297
+ return JSON.parse(legacyData);
7298
+ }
7299
+ catch (legacyError) {
7300
+ // If the legacy file doesn't exist either, return null
7301
+ if (legacyError.code === 'ENOENT') {
7302
+ return null;
7303
+ }
7304
+ throw legacyError;
7305
+ }
7306
+ }
7307
+ throw yesterdayError;
7308
+ }
7309
+ }
7310
+ throw currentError;
7311
+ }
6914
7312
  }
6915
7313
  catch (error) {
6916
- // If the file doesn't exist, return null
6917
- if (error.code === 'ENOENT') {
6918
- return null;
6919
- }
6920
7314
  console.error('Error getting statistics data:', error);
6921
7315
  throw error;
6922
7316
  }
@@ -6960,6 +7354,16 @@ class S3CompatibleStorage extends BaseStorage {
6960
7354
  this.s3Client = null;
6961
7355
  // Statistics caching for better performance
6962
7356
  this.statisticsCache = null;
7357
+ // Batch update timer ID
7358
+ this.statisticsBatchUpdateTimerId = null;
7359
+ // Flag to indicate if statistics have been modified since last save
7360
+ this.statisticsModified = false;
7361
+ // Time of last statistics flush to storage
7362
+ this.lastStatisticsFlushTime = 0;
7363
+ // Minimum time between statistics flushes (5 seconds)
7364
+ this.MIN_FLUSH_INTERVAL_MS = 5000;
7365
+ // Maximum time to wait before flushing statistics (30 seconds)
7366
+ this.MAX_FLUSH_DELAY_MS = 30000;
6963
7367
  this.bucketName = options.bucketName;
6964
7368
  this.region = options.region || 'auto';
6965
7369
  this.endpoint = options.endpoint;
@@ -7018,6 +7422,12 @@ class S3CompatibleStorage extends BaseStorage {
7018
7422
  throw new Error(`Failed to initialize ${this.serviceType} storage: ${error}`);
7019
7423
  }
7020
7424
  }
7425
+ /**
7426
+ * Save a noun to storage (internal implementation)
7427
+ */
7428
+ async saveNoun_internal(noun) {
7429
+ return this.saveNode(noun);
7430
+ }
7021
7431
  /**
7022
7432
  * Save a node to storage
7023
7433
  */
@@ -7067,6 +7477,12 @@ class S3CompatibleStorage extends BaseStorage {
7067
7477
  throw new Error(`Failed to save node ${node.id}: ${error}`);
7068
7478
  }
7069
7479
  }
7480
+ /**
7481
+ * Get a noun from storage (internal implementation)
7482
+ */
7483
+ async getNoun_internal(id) {
7484
+ return this.getNode(id);
7485
+ }
7070
7486
  /**
7071
7487
  * Get a node from storage
7072
7488
  */
@@ -7124,6 +7540,12 @@ class S3CompatibleStorage extends BaseStorage {
7124
7540
  return null;
7125
7541
  }
7126
7542
  }
7543
+ /**
7544
+ * Get all nouns from storage (internal implementation)
7545
+ */
7546
+ async getAllNouns_internal() {
7547
+ return this.getAllNodes();
7548
+ }
7127
7549
  /**
7128
7550
  * Get all nodes from storage
7129
7551
  */
@@ -7222,6 +7644,14 @@ class S3CompatibleStorage extends BaseStorage {
7222
7644
  return [];
7223
7645
  }
7224
7646
  }
7647
+ /**
7648
+ * Get nouns by noun type (internal implementation)
7649
+ * @param nounType The noun type to filter by
7650
+ * @returns Promise that resolves to an array of nouns of the specified noun type
7651
+ */
7652
+ async getNounsByNounType_internal(nounType) {
7653
+ return this.getNodesByNounType(nounType);
7654
+ }
7225
7655
  /**
7226
7656
  * Get nodes by noun type
7227
7657
  * @param nounType The noun type to filter by
@@ -7247,6 +7677,12 @@ class S3CompatibleStorage extends BaseStorage {
7247
7677
  return [];
7248
7678
  }
7249
7679
  }
7680
+ /**
7681
+ * Delete a noun from storage (internal implementation)
7682
+ */
7683
+ async deleteNoun_internal(id) {
7684
+ return this.deleteNode(id);
7685
+ }
7250
7686
  /**
7251
7687
  * Delete a node from storage
7252
7688
  */
@@ -7266,6 +7702,12 @@ class S3CompatibleStorage extends BaseStorage {
7266
7702
  throw new Error(`Failed to delete node ${id}: ${error}`);
7267
7703
  }
7268
7704
  }
7705
+ /**
7706
+ * Save a verb to storage (internal implementation)
7707
+ */
7708
+ async saveVerb_internal(verb) {
7709
+ return this.saveEdge(verb);
7710
+ }
7269
7711
  /**
7270
7712
  * Save an edge to storage
7271
7713
  */
@@ -7292,6 +7734,12 @@ class S3CompatibleStorage extends BaseStorage {
7292
7734
  throw new Error(`Failed to save edge ${edge.id}: ${error}`);
7293
7735
  }
7294
7736
  }
7737
+ /**
7738
+ * Get a verb from storage (internal implementation)
7739
+ */
7740
+ async getVerb_internal(id) {
7741
+ return this.getEdge(id);
7742
+ }
7295
7743
  /**
7296
7744
  * Get an edge from storage
7297
7745
  */
@@ -7322,7 +7770,9 @@ class S3CompatibleStorage extends BaseStorage {
7322
7770
  console.log(`Parsed edge data for ${id}:`, parsedEdge);
7323
7771
  // Ensure the parsed edge has the expected properties
7324
7772
  if (!parsedEdge || !parsedEdge.id || !parsedEdge.vector || !parsedEdge.connections ||
7325
- !parsedEdge.sourceId || !parsedEdge.targetId || !parsedEdge.type) {
7773
+ !(parsedEdge.sourceId || parsedEdge.source) ||
7774
+ !(parsedEdge.targetId || parsedEdge.target) ||
7775
+ !(parsedEdge.type || parsedEdge.verb)) {
7326
7776
  console.error(`Invalid edge data for ${id}:`, parsedEdge);
7327
7777
  return null;
7328
7778
  }
@@ -7331,15 +7781,31 @@ class S3CompatibleStorage extends BaseStorage {
7331
7781
  for (const [level, nodeIds] of Object.entries(parsedEdge.connections)) {
7332
7782
  connections.set(Number(level), new Set(nodeIds));
7333
7783
  }
7784
+ // Create default timestamp if not present
7785
+ const defaultTimestamp = {
7786
+ seconds: Math.floor(Date.now() / 1000),
7787
+ nanoseconds: (Date.now() % 1000) * 1000000
7788
+ };
7789
+ // Create default createdBy if not present
7790
+ const defaultCreatedBy = {
7791
+ augmentation: 'unknown',
7792
+ version: '1.0'
7793
+ };
7334
7794
  const edge = {
7335
7795
  id: parsedEdge.id,
7336
7796
  vector: parsedEdge.vector,
7337
7797
  connections,
7338
- sourceId: parsedEdge.sourceId,
7339
- targetId: parsedEdge.targetId,
7340
- type: parsedEdge.type,
7798
+ sourceId: parsedEdge.sourceId || parsedEdge.source,
7799
+ targetId: parsedEdge.targetId || parsedEdge.target,
7800
+ source: parsedEdge.sourceId || parsedEdge.source,
7801
+ target: parsedEdge.targetId || parsedEdge.target,
7802
+ verb: parsedEdge.type || parsedEdge.verb,
7803
+ type: parsedEdge.type || parsedEdge.verb,
7341
7804
  weight: parsedEdge.weight || 1.0, // Default weight if not provided
7342
- metadata: parsedEdge.metadata || {}
7805
+ metadata: parsedEdge.metadata || {},
7806
+ createdAt: parsedEdge.createdAt || defaultTimestamp,
7807
+ updatedAt: parsedEdge.updatedAt || defaultTimestamp,
7808
+ createdBy: parsedEdge.createdBy || defaultCreatedBy
7343
7809
  };
7344
7810
  console.log(`Successfully retrieved edge ${id}:`, edge);
7345
7811
  return edge;
@@ -7355,6 +7821,12 @@ class S3CompatibleStorage extends BaseStorage {
7355
7821
  return null;
7356
7822
  }
7357
7823
  }
7824
+ /**
7825
+ * Get all verbs from storage (internal implementation)
7826
+ */
7827
+ async getAllVerbs_internal() {
7828
+ return this.getAllEdges();
7829
+ }
7358
7830
  /**
7359
7831
  * Get all edges from storage
7360
7832
  */
@@ -7391,15 +7863,31 @@ class S3CompatibleStorage extends BaseStorage {
7391
7863
  for (const [level, nodeIds] of Object.entries(parsedEdge.connections)) {
7392
7864
  connections.set(Number(level), new Set(nodeIds));
7393
7865
  }
7866
+ // Create default timestamp if not present
7867
+ const defaultTimestamp = {
7868
+ seconds: Math.floor(Date.now() / 1000),
7869
+ nanoseconds: (Date.now() % 1000) * 1000000
7870
+ };
7871
+ // Create default createdBy if not present
7872
+ const defaultCreatedBy = {
7873
+ augmentation: 'unknown',
7874
+ version: '1.0'
7875
+ };
7394
7876
  return {
7395
7877
  id: parsedEdge.id,
7396
7878
  vector: parsedEdge.vector,
7397
7879
  connections,
7398
- sourceId: parsedEdge.sourceId,
7399
- targetId: parsedEdge.targetId,
7400
- type: parsedEdge.type,
7401
- weight: parsedEdge.weight,
7402
- metadata: parsedEdge.metadata
7880
+ sourceId: parsedEdge.sourceId || parsedEdge.source,
7881
+ targetId: parsedEdge.targetId || parsedEdge.target,
7882
+ source: parsedEdge.sourceId || parsedEdge.source,
7883
+ target: parsedEdge.targetId || parsedEdge.target,
7884
+ verb: parsedEdge.type || parsedEdge.verb,
7885
+ type: parsedEdge.type || parsedEdge.verb,
7886
+ weight: parsedEdge.weight || 1.0,
7887
+ metadata: parsedEdge.metadata || {},
7888
+ createdAt: parsedEdge.createdAt || defaultTimestamp,
7889
+ updatedAt: parsedEdge.updatedAt || defaultTimestamp,
7890
+ createdBy: parsedEdge.createdBy || defaultCreatedBy
7403
7891
  };
7404
7892
  }
7405
7893
  catch (error) {
@@ -7416,26 +7904,50 @@ class S3CompatibleStorage extends BaseStorage {
7416
7904
  return [];
7417
7905
  }
7418
7906
  }
7907
+ /**
7908
+ * Get verbs by source (internal implementation)
7909
+ */
7910
+ async getVerbsBySource_internal(sourceId) {
7911
+ return this.getEdgesBySource(sourceId);
7912
+ }
7419
7913
  /**
7420
7914
  * Get edges by source
7421
7915
  */
7422
7916
  async getEdgesBySource(sourceId) {
7423
7917
  const edges = await this.getAllEdges();
7424
- return edges.filter((edge) => edge.sourceId === sourceId);
7918
+ return edges.filter((edge) => (edge.sourceId || edge.source) === sourceId);
7919
+ }
7920
+ /**
7921
+ * Get verbs by target (internal implementation)
7922
+ */
7923
+ async getVerbsByTarget_internal(targetId) {
7924
+ return this.getEdgesByTarget(targetId);
7425
7925
  }
7426
7926
  /**
7427
7927
  * Get edges by target
7428
7928
  */
7429
7929
  async getEdgesByTarget(targetId) {
7430
7930
  const edges = await this.getAllEdges();
7431
- return edges.filter((edge) => edge.targetId === targetId);
7931
+ return edges.filter((edge) => (edge.targetId || edge.target) === targetId);
7932
+ }
7933
+ /**
7934
+ * Get verbs by type (internal implementation)
7935
+ */
7936
+ async getVerbsByType_internal(type) {
7937
+ return this.getEdgesByType(type);
7432
7938
  }
7433
7939
  /**
7434
7940
  * Get edges by type
7435
7941
  */
7436
7942
  async getEdgesByType(type) {
7437
7943
  const edges = await this.getAllEdges();
7438
- return edges.filter((edge) => edge.type === type);
7944
+ return edges.filter((edge) => (edge.type || edge.verb) === type);
7945
+ }
7946
+ /**
7947
+ * Delete a verb from storage (internal implementation)
7948
+ */
7949
+ async deleteVerb_internal(id) {
7950
+ return this.deleteEdge(id);
7439
7951
  }
7440
7952
  /**
7441
7953
  * Delete an edge from storage
@@ -7723,6 +8235,102 @@ class S3CompatibleStorage extends BaseStorage {
7723
8235
  };
7724
8236
  }
7725
8237
  }
8238
+ /**
8239
+ * Get the statistics key for a specific date
8240
+ * @param date The date to get the key for
8241
+ * @returns The statistics key for the specified date
8242
+ */
8243
+ getStatisticsKeyForDate(date) {
8244
+ const year = date.getUTCFullYear();
8245
+ const month = String(date.getUTCMonth() + 1).padStart(2, '0');
8246
+ const day = String(date.getUTCDate()).padStart(2, '0');
8247
+ return `${this.indexPrefix}${STATISTICS_KEY}_${year}${month}${day}.json`;
8248
+ }
8249
+ /**
8250
+ * Get the current statistics key
8251
+ * @returns The current statistics key
8252
+ */
8253
+ getCurrentStatisticsKey() {
8254
+ return this.getStatisticsKeyForDate(new Date());
8255
+ }
8256
+ /**
8257
+ * Get the legacy statistics key (for backward compatibility)
8258
+ * @returns The legacy statistics key
8259
+ */
8260
+ getLegacyStatisticsKey() {
8261
+ return `${this.indexPrefix}${STATISTICS_KEY}.json`;
8262
+ }
8263
+ /**
8264
+ * Schedule a batch update of statistics
8265
+ */
8266
+ scheduleBatchUpdate() {
8267
+ // Mark statistics as modified
8268
+ this.statisticsModified = true;
8269
+ // If a timer is already set, don't set another one
8270
+ if (this.statisticsBatchUpdateTimerId !== null) {
8271
+ return;
8272
+ }
8273
+ // Calculate time since last flush
8274
+ const now = Date.now();
8275
+ const timeSinceLastFlush = now - this.lastStatisticsFlushTime;
8276
+ // If we've recently flushed, wait longer before the next flush
8277
+ const delayMs = timeSinceLastFlush < this.MIN_FLUSH_INTERVAL_MS
8278
+ ? this.MAX_FLUSH_DELAY_MS
8279
+ : this.MIN_FLUSH_INTERVAL_MS;
8280
+ // Schedule the batch update
8281
+ this.statisticsBatchUpdateTimerId = setTimeout(() => {
8282
+ this.flushStatistics();
8283
+ }, delayMs);
8284
+ }
8285
+ /**
8286
+ * Flush statistics to storage
8287
+ */
8288
+ async flushStatistics() {
8289
+ // Clear the timer
8290
+ if (this.statisticsBatchUpdateTimerId !== null) {
8291
+ clearTimeout(this.statisticsBatchUpdateTimerId);
8292
+ this.statisticsBatchUpdateTimerId = null;
8293
+ }
8294
+ // If statistics haven't been modified, no need to flush
8295
+ if (!this.statisticsModified || !this.statisticsCache) {
8296
+ return;
8297
+ }
8298
+ try {
8299
+ // Import the PutObjectCommand only when needed
8300
+ const { PutObjectCommand } = await import('@aws-sdk/client-s3');
8301
+ // Get the current statistics key
8302
+ const key = this.getCurrentStatisticsKey();
8303
+ const body = JSON.stringify(this.statisticsCache, null, 2);
8304
+ // Save the statistics to S3-compatible storage
8305
+ await this.s3Client.send(new PutObjectCommand({
8306
+ Bucket: this.bucketName,
8307
+ Key: key,
8308
+ Body: body,
8309
+ ContentType: 'application/json'
8310
+ }));
8311
+ // Update the last flush time
8312
+ this.lastStatisticsFlushTime = Date.now();
8313
+ // Reset the modified flag
8314
+ this.statisticsModified = false;
8315
+ // Also update the legacy key for backward compatibility, but less frequently
8316
+ // Only update it once every 10 flushes (approximately)
8317
+ if (Math.random() < 0.1) {
8318
+ const legacyKey = this.getLegacyStatisticsKey();
8319
+ await this.s3Client.send(new PutObjectCommand({
8320
+ Bucket: this.bucketName,
8321
+ Key: legacyKey,
8322
+ Body: body,
8323
+ ContentType: 'application/json'
8324
+ }));
8325
+ }
8326
+ }
8327
+ catch (error) {
8328
+ console.error('Failed to flush statistics data:', error);
8329
+ // Mark as still modified so we'll try again later
8330
+ this.statisticsModified = true;
8331
+ // Don't throw the error to avoid disrupting the application
8332
+ }
8333
+ }
7726
8334
  /**
7727
8335
  * Save statistics data to storage
7728
8336
  * @param statistics The statistics data to save
@@ -7738,17 +8346,8 @@ class S3CompatibleStorage extends BaseStorage {
7738
8346
  hnswIndexSize: statistics.hnswIndexSize,
7739
8347
  lastUpdated: statistics.lastUpdated
7740
8348
  };
7741
- // Import the PutObjectCommand only when needed
7742
- const { PutObjectCommand } = await import('@aws-sdk/client-s3');
7743
- const key = `${this.indexPrefix}${STATISTICS_KEY}.json`;
7744
- const body = JSON.stringify(statistics, null, 2);
7745
- // Save the statistics to S3-compatible storage
7746
- await this.s3Client.send(new PutObjectCommand({
7747
- Bucket: this.bucketName,
7748
- Key: key,
7749
- Body: body,
7750
- ContentType: 'application/json'
7751
- }));
8349
+ // Schedule a batch update instead of saving immediately
8350
+ this.scheduleBatchUpdate();
7752
8351
  }
7753
8352
  catch (error) {
7754
8353
  console.error('Failed to save statistics data:', error);
@@ -7774,8 +8373,49 @@ class S3CompatibleStorage extends BaseStorage {
7774
8373
  try {
7775
8374
  // Import the GetObjectCommand only when needed
7776
8375
  const { GetObjectCommand } = await import('@aws-sdk/client-s3');
7777
- const key = `${this.indexPrefix}${STATISTICS_KEY}.json`;
7778
- // Try to get the statistics from the index directory
8376
+ // First try to get statistics from today's file
8377
+ const currentKey = this.getCurrentStatisticsKey();
8378
+ let statistics = await this.tryGetStatisticsFromKey(currentKey);
8379
+ // If not found, try yesterday's file (in case it's just after midnight)
8380
+ if (!statistics) {
8381
+ const yesterday = new Date();
8382
+ yesterday.setDate(yesterday.getDate() - 1);
8383
+ const yesterdayKey = this.getStatisticsKeyForDate(yesterday);
8384
+ statistics = await this.tryGetStatisticsFromKey(yesterdayKey);
8385
+ }
8386
+ // If still not found, try the legacy location
8387
+ if (!statistics) {
8388
+ const legacyKey = this.getLegacyStatisticsKey();
8389
+ statistics = await this.tryGetStatisticsFromKey(legacyKey);
8390
+ }
8391
+ // If we found statistics, update the cache
8392
+ if (statistics) {
8393
+ // Update the cache with a deep copy
8394
+ this.statisticsCache = {
8395
+ nounCount: { ...statistics.nounCount },
8396
+ verbCount: { ...statistics.verbCount },
8397
+ metadataCount: { ...statistics.metadataCount },
8398
+ hnswIndexSize: statistics.hnswIndexSize,
8399
+ lastUpdated: statistics.lastUpdated
8400
+ };
8401
+ }
8402
+ return statistics;
8403
+ }
8404
+ catch (error) {
8405
+ console.error('Error getting statistics data:', error);
8406
+ throw error;
8407
+ }
8408
+ }
8409
+ /**
8410
+ * Try to get statistics from a specific key
8411
+ * @param key The key to try to get statistics from
8412
+ * @returns The statistics data or null if not found
8413
+ */
8414
+ async tryGetStatisticsFromKey(key) {
8415
+ try {
8416
+ // Import the GetObjectCommand only when needed
8417
+ const { GetObjectCommand } = await import('@aws-sdk/client-s3');
8418
+ // Try to get the statistics from the specified key
7779
8419
  const response = await this.s3Client.send(new GetObjectCommand({
7780
8420
  Bucket: this.bucketName,
7781
8421
  Key: key
@@ -7786,17 +8426,8 @@ class S3CompatibleStorage extends BaseStorage {
7786
8426
  }
7787
8427
  // Convert the response body to a string
7788
8428
  const bodyContents = await response.Body.transformToString();
7789
- // Parse the JSON string and update the cache
7790
- const statistics = JSON.parse(bodyContents);
7791
- // Update the cache with a deep copy
7792
- this.statisticsCache = {
7793
- nounCount: { ...statistics.nounCount },
7794
- verbCount: { ...statistics.verbCount },
7795
- metadataCount: { ...statistics.metadataCount },
7796
- hnswIndexSize: statistics.hnswIndexSize,
7797
- lastUpdated: statistics.lastUpdated
7798
- };
7799
- return statistics;
8429
+ // Parse the JSON string
8430
+ return JSON.parse(bodyContents);
7800
8431
  }
7801
8432
  catch (error) {
7802
8433
  // Check if this is a "NoSuchKey" error (object doesn't exist)
@@ -7806,7 +8437,7 @@ class S3CompatibleStorage extends BaseStorage {
7806
8437
  error.message.includes('does not exist')))) {
7807
8438
  return null;
7808
8439
  }
7809
- console.error('Error getting statistics data:', error);
8440
+ // For other errors, propagate them
7810
8441
  throw error;
7811
8442
  }
7812
8443
  }
@@ -11325,16 +11956,32 @@ class BrainyData {
11325
11956
  verbType = VerbType.RelatedTo;
11326
11957
  }
11327
11958
  }
11959
+ // Get service name from options or current augmentation
11960
+ const service = options.service || this.getCurrentAugmentation();
11961
+ // Create timestamp for creation/update time
11962
+ const now = new Date();
11963
+ const timestamp = {
11964
+ seconds: Math.floor(now.getTime() / 1000),
11965
+ nanoseconds: (now.getTime() % 1000) * 1000000
11966
+ };
11328
11967
  // Create verb
11329
11968
  const verb = {
11330
11969
  id,
11331
11970
  vector: verbVector,
11332
11971
  connections: new Map(),
11333
- sourceId,
11334
- targetId,
11335
- type: verbType,
11972
+ sourceId: sourceId,
11973
+ targetId: targetId,
11974
+ source: sourceId,
11975
+ target: targetId,
11976
+ verb: verbType,
11336
11977
  weight: options.weight,
11337
- metadata: options.metadata
11978
+ metadata: options.metadata,
11979
+ createdAt: timestamp,
11980
+ updatedAt: timestamp,
11981
+ createdBy: {
11982
+ augmentation: service,
11983
+ version: '1.0' // TODO: Get actual version from augmentation
11984
+ }
11338
11985
  };
11339
11986
  // Add to index
11340
11987
  await this.index.addItem({ id, vector: verbVector });
@@ -11348,8 +11995,8 @@ class BrainyData {
11348
11995
  // Save verb to storage
11349
11996
  await this.storage.saveVerb(verb);
11350
11997
  // Track verb statistics
11351
- const service = options.service || 'default';
11352
- await this.storage.incrementStatistic('verb', service);
11998
+ const serviceForStats = options.service || 'default';
11999
+ await this.storage.incrementStatistic('verb', serviceForStats);
11353
12000
  // Update HNSW index size (excluding verbs)
11354
12001
  await this.storage.updateHnswIndexSize(await this.getNounCount());
11355
12002
  return id;