@soulcraft/brainy 3.25.0 → 3.25.2

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/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [3.25.2](https://github.com/soulcraftlabs/brainy/compare/v3.25.1...v3.25.2) (2025-10-08)
6
+
7
+
8
+ ### 🐛 Bug Fixes
9
+
10
+ * export ImportManager and add getStats() convenience method ([06b3bc7](https://github.com/soulcraftlabs/brainy/commit/06b3bc77e1fd4c5544dc61cccd4814bd7a26a1dd))
11
+
12
+ ### [3.25.1](https://github.com/soulcraftlabs/brainy/compare/v3.25.0...v3.25.1) (2025-10-07)
13
+
14
+
15
+ ### 🐛 Bug Fixes
16
+
17
+ * implement stub methods in Neural API clustering ([1d2da82](https://github.com/soulcraftlabs/brainy/commit/1d2da823ede478e6b1bd5144be58ca4921e951e7))
18
+
19
+
20
+ ### ✅ Tests
21
+
22
+ * use memory storage for domain-time clustering tests ([34fb6e0](https://github.com/soulcraftlabs/brainy/commit/34fb6e05b5a04f2c8fc635ca36c9b96ee19e3130))
23
+
5
24
  ### [3.25.0](https://github.com/soulcraftlabs/brainy/compare/v3.24.0...v3.25.0) (2025-10-07)
6
25
 
7
26
  - test: skip GitBridge Integration test (empty suite) (8939f59)
package/dist/brainy.d.ts CHANGED
@@ -809,6 +809,27 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
809
809
  get: (name: string) => import("./augmentations/brainyAugmentation.js").BrainyAugmentation;
810
810
  has: (name: string) => boolean;
811
811
  };
812
+ /**
813
+ * Get complete statistics - convenience method
814
+ * For more granular counting, use brain.counts API
815
+ * @returns Complete statistics including entities, relationships, and density
816
+ */
817
+ getStats(): {
818
+ entities: {
819
+ total: number;
820
+ byType: {
821
+ [k: string]: number;
822
+ };
823
+ };
824
+ relationships: {
825
+ totalRelationships: number;
826
+ relationshipsByType: Record<string, number>;
827
+ uniqueSourceNodes: number;
828
+ uniqueTargetNodes: number;
829
+ totalNodes: number;
830
+ };
831
+ density: number;
832
+ };
812
833
  /**
813
834
  * Parse natural language query using advanced NLP with 220+ patterns
814
835
  * The embedding model is always available as it's core to Brainy's functionality
package/dist/brainy.js CHANGED
@@ -1768,6 +1768,14 @@ export class Brainy {
1768
1768
  has: (name) => this.augmentationRegistry.getAll().some(a => a.name === name)
1769
1769
  };
1770
1770
  }
1771
+ /**
1772
+ * Get complete statistics - convenience method
1773
+ * For more granular counting, use brain.counts API
1774
+ * @returns Complete statistics including entities, relationships, and density
1775
+ */
1776
+ getStats() {
1777
+ return this.counts.getStats();
1778
+ }
1771
1779
  // ============= HELPER METHODS =============
1772
1780
  /**
1773
1781
  * Parse natural language query using advanced NLP with 220+ patterns
package/dist/index.d.ts CHANGED
@@ -15,6 +15,8 @@ export { PresetName, ModelPrecision, StorageOption, FeatureSet, DistributedRole,
15
15
  export { Cortex, cortex } from './cortex.js';
16
16
  export { NeuralImport } from './cortex/neuralImport.js';
17
17
  export type { NeuralAnalysisResult, DetectedEntity, DetectedRelationship, NeuralInsight, NeuralImportOptions } from './cortex/neuralImport.js';
18
+ export { ImportManager, createImportManager } from './importManager.js';
19
+ export type { ImportOptions, ImportResult } from './importManager.js';
18
20
  import { euclideanDistance, cosineDistance, manhattanDistance, dotProductDistance } from './utils/index.js';
19
21
  export { euclideanDistance, cosineDistance, manhattanDistance, dotProductDistance };
20
22
  export { getBrainyVersion } from './utils/version.js';
package/dist/index.js CHANGED
@@ -31,6 +31,8 @@ getPreset, isValidPreset, getPresetsByCategory, getAllPresetNames, getPresetDesc
31
31
  export { Cortex, cortex } from './cortex.js';
32
32
  // Export Neural Import (AI data understanding)
33
33
  export { NeuralImport } from './cortex/neuralImport.js';
34
+ // Export Import Manager (comprehensive data import)
35
+ export { ImportManager, createImportManager } from './importManager.js';
34
36
  // Augmentation types are already exported later in the file
35
37
  // Export distance functions for convenience
36
38
  import { euclideanDistance, cosineDistance, manhattanDistance, dotProductDistance } from './utils/index.js';
@@ -293,6 +293,7 @@ export declare class ImprovedNeuralAPI {
293
293
  private _calculateDomainConfidence;
294
294
  private _findCrossDomainMembers;
295
295
  private _findCrossDomainClusters;
296
+ private _averageVectors;
296
297
  private _getItemsByTimeWindow;
297
298
  private _calculateTemporalMetrics;
298
299
  private _mergeOverlappingTemporalClusters;
@@ -1899,8 +1899,63 @@ export class ImprovedNeuralAPI {
1899
1899
  return Math.max(0, 1 - (avgDistance / maxDistance));
1900
1900
  }
1901
1901
  async _getItemsByField(field) {
1902
- // Implementation would query items by metadata field
1903
- return [];
1902
+ try {
1903
+ // Query all items from brain (limit to reasonable number for clustering)
1904
+ const result = await this.brain.find({
1905
+ query: '',
1906
+ limit: 10000 // Max items for clustering
1907
+ });
1908
+ if (!result || !Array.isArray(result)) {
1909
+ return [];
1910
+ }
1911
+ // Filter items that have the specified field (check both root level and metadata)
1912
+ const itemsWithField = result.filter((item) => {
1913
+ if (!item || !item.entity)
1914
+ return false;
1915
+ const entity = item.entity;
1916
+ // Check root level fields first (e.g., 'noun' for type)
1917
+ if (field === 'type' || field === 'nounType') {
1918
+ return entity.noun != null;
1919
+ }
1920
+ // Check if field exists at root level
1921
+ if (entity[field] != null) {
1922
+ return true;
1923
+ }
1924
+ // Check if field exists in metadata/data
1925
+ if (entity.metadata?.[field] != null) {
1926
+ return true;
1927
+ }
1928
+ if (entity.data?.[field] != null) {
1929
+ return true;
1930
+ }
1931
+ return false;
1932
+ });
1933
+ // Map to format expected by clustering methods
1934
+ return itemsWithField.map((item) => {
1935
+ const entity = item.entity;
1936
+ return {
1937
+ id: entity.id,
1938
+ vector: entity.embedding || entity.vector || [],
1939
+ metadata: {
1940
+ ...(entity.metadata || {}),
1941
+ ...(entity.data || {}),
1942
+ // Include root-level fields in metadata for easy access
1943
+ noun: entity.noun,
1944
+ type: entity.noun,
1945
+ createdAt: entity.createdAt,
1946
+ updatedAt: entity.updatedAt,
1947
+ label: entity.label
1948
+ },
1949
+ nounType: entity.noun,
1950
+ label: entity.label || entity.data || '',
1951
+ data: entity.data
1952
+ };
1953
+ });
1954
+ }
1955
+ catch (error) {
1956
+ console.error('Error in _getItemsByField:', error);
1957
+ return [];
1958
+ }
1904
1959
  }
1905
1960
  // ===== TRIPLE INTELLIGENCE INTEGRATION =====
1906
1961
  /**
@@ -2262,11 +2317,34 @@ export class ImprovedNeuralAPI {
2262
2317
  _groupByDomain(items, field) {
2263
2318
  const groups = new Map();
2264
2319
  for (const item of items) {
2265
- const domain = item.metadata?.[field] || 'unknown';
2266
- if (!groups.has(domain)) {
2267
- groups.set(domain, []);
2320
+ // Check multiple locations for the field value
2321
+ let domain = 'unknown';
2322
+ // Special handling for type/nounType field
2323
+ if (field === 'type' || field === 'nounType') {
2324
+ domain = item.nounType || item.metadata?.noun || item.metadata?.type || 'unknown';
2268
2325
  }
2269
- groups.get(domain).push(item);
2326
+ else {
2327
+ // Check root level first
2328
+ domain = item[field];
2329
+ // Then check metadata
2330
+ if (domain == null) {
2331
+ domain = item.metadata?.[field];
2332
+ }
2333
+ // Then check data
2334
+ if (domain == null) {
2335
+ domain = item.data?.[field];
2336
+ }
2337
+ // Fallback to unknown
2338
+ if (domain == null) {
2339
+ domain = 'unknown';
2340
+ }
2341
+ }
2342
+ // Convert domain to string for Map key
2343
+ const domainKey = String(domain);
2344
+ if (!groups.has(domainKey)) {
2345
+ groups.set(domainKey, []);
2346
+ }
2347
+ groups.get(domainKey).push(item);
2270
2348
  }
2271
2349
  return groups;
2272
2350
  }
@@ -2283,16 +2361,177 @@ export class ImprovedNeuralAPI {
2283
2361
  return (density * 0.3 + coherence * 0.3 + domainRelevance * 0.4); // Weighted average
2284
2362
  }
2285
2363
  async _findCrossDomainMembers(cluster, threshold) {
2286
- // Find members that might belong to multiple domains
2287
- return [];
2364
+ try {
2365
+ // Find cluster members that have high similarity to items in other domains
2366
+ const crossDomainMembers = [];
2367
+ for (const memberId of cluster.members) {
2368
+ try {
2369
+ // Get neighbors for this member
2370
+ const neighbors = await this.neighbors(memberId, {
2371
+ limit: 10,
2372
+ minSimilarity: threshold
2373
+ });
2374
+ if (Array.isArray(neighbors) && neighbors.length > 0) {
2375
+ // Check if any neighbors are NOT in this cluster
2376
+ const hasExternalNeighbors = neighbors.some(neighbor => !cluster.members.includes(typeof neighbor === 'object' ? neighbor.id : neighbor));
2377
+ if (hasExternalNeighbors) {
2378
+ crossDomainMembers.push(memberId);
2379
+ }
2380
+ }
2381
+ }
2382
+ catch (error) {
2383
+ // Skip members that can't be processed
2384
+ continue;
2385
+ }
2386
+ }
2387
+ return crossDomainMembers;
2388
+ }
2389
+ catch (error) {
2390
+ console.error('Error in _findCrossDomainMembers:', error);
2391
+ return [];
2392
+ }
2288
2393
  }
2289
2394
  async _findCrossDomainClusters(clusters, threshold) {
2290
- // Find clusters that span multiple domains
2291
- return [];
2395
+ try {
2396
+ const crossDomainClusters = [];
2397
+ // Group clusters by domain
2398
+ const domainMap = new Map();
2399
+ for (const cluster of clusters) {
2400
+ const domain = cluster.domain || 'unknown';
2401
+ if (!domainMap.has(domain)) {
2402
+ domainMap.set(domain, []);
2403
+ }
2404
+ domainMap.get(domain).push(cluster);
2405
+ }
2406
+ // Find clusters with high inter-domain similarity
2407
+ const domains = Array.from(domainMap.keys());
2408
+ for (let i = 0; i < domains.length; i++) {
2409
+ for (let j = i + 1; j < domains.length; j++) {
2410
+ const domain1 = domains[i];
2411
+ const domain2 = domains[j];
2412
+ const clusters1 = domainMap.get(domain1);
2413
+ const clusters2 = domainMap.get(domain2);
2414
+ // Compare clusters between domains
2415
+ for (const c1 of clusters1) {
2416
+ for (const c2 of clusters2) {
2417
+ try {
2418
+ // Calculate similarity between cluster centroids
2419
+ if (!c1.centroid || !c2.centroid || c1.centroid.length === 0 || c2.centroid.length === 0) {
2420
+ continue;
2421
+ }
2422
+ const similarity = 1 - cosineDistance(Array.from(c1.centroid), Array.from(c2.centroid));
2423
+ if (similarity >= threshold) {
2424
+ // Create a cross-domain cluster
2425
+ const mergedMembers = [...new Set([...c1.members, ...c2.members])];
2426
+ const mergedCentroid = this._averageVectors([
2427
+ Array.from(c1.centroid),
2428
+ Array.from(c2.centroid)
2429
+ ]);
2430
+ crossDomainClusters.push({
2431
+ ...c1,
2432
+ id: `cross-${domain1}-${domain2}-${crossDomainClusters.length}`,
2433
+ label: `Cross-domain: ${c1.label} + ${c2.label}`,
2434
+ members: mergedMembers,
2435
+ centroid: mergedCentroid,
2436
+ domain: `${domain1}+${domain2}`,
2437
+ domainConfidence: similarity,
2438
+ crossDomainMembers: mergedMembers
2439
+ });
2440
+ }
2441
+ }
2442
+ catch (error) {
2443
+ // Skip cluster pairs that can't be compared
2444
+ continue;
2445
+ }
2446
+ }
2447
+ }
2448
+ }
2449
+ }
2450
+ return crossDomainClusters;
2451
+ }
2452
+ catch (error) {
2453
+ console.error('Error in _findCrossDomainClusters:', error);
2454
+ return [];
2455
+ }
2456
+ }
2457
+ _averageVectors(vectors) {
2458
+ if (vectors.length === 0)
2459
+ return [];
2460
+ if (vectors.length === 1)
2461
+ return [...vectors[0]];
2462
+ const dim = vectors[0].length;
2463
+ const result = new Array(dim).fill(0);
2464
+ for (const vector of vectors) {
2465
+ for (let i = 0; i < dim; i++) {
2466
+ result[i] += vector[i];
2467
+ }
2468
+ }
2469
+ for (let i = 0; i < dim; i++) {
2470
+ result[i] /= vectors.length;
2471
+ }
2472
+ return result;
2292
2473
  }
2293
2474
  async _getItemsByTimeWindow(timeField, window) {
2294
- // Implementation would query items within time window
2295
- return [];
2475
+ try {
2476
+ // Query all items from brain
2477
+ const result = await this.brain.find({
2478
+ query: '',
2479
+ limit: 10000 // Max items for clustering
2480
+ });
2481
+ if (!result || !Array.isArray(result)) {
2482
+ return [];
2483
+ }
2484
+ // Filter items within the time window
2485
+ const itemsInWindow = result.filter((item) => {
2486
+ if (!item || !item.entity)
2487
+ return false;
2488
+ const entity = item.entity;
2489
+ // Get timestamp value from various possible locations
2490
+ let timestamp = null;
2491
+ // Check root level first
2492
+ if (timeField === 'createdAt' || timeField === 'updatedAt') {
2493
+ timestamp = entity[timeField];
2494
+ }
2495
+ // Check metadata/data
2496
+ if (timestamp == null) {
2497
+ timestamp = entity.metadata?.[timeField] || entity.data?.[timeField];
2498
+ }
2499
+ if (timestamp == null) {
2500
+ return false;
2501
+ }
2502
+ // Convert to Date if needed
2503
+ const itemDate = timestamp instanceof Date ? timestamp : new Date(timestamp);
2504
+ if (isNaN(itemDate.getTime())) {
2505
+ return false; // Invalid date
2506
+ }
2507
+ // Check if item falls within window
2508
+ return itemDate >= window.start && itemDate <= window.end;
2509
+ });
2510
+ // Map to format expected by clustering methods
2511
+ return itemsInWindow.map((item) => {
2512
+ const entity = item.entity;
2513
+ return {
2514
+ id: entity.id,
2515
+ vector: entity.embedding || entity.vector || [],
2516
+ metadata: {
2517
+ ...(entity.metadata || {}),
2518
+ ...(entity.data || {}),
2519
+ noun: entity.noun,
2520
+ type: entity.noun,
2521
+ createdAt: entity.createdAt,
2522
+ updatedAt: entity.updatedAt,
2523
+ label: entity.label
2524
+ },
2525
+ nounType: entity.noun,
2526
+ label: entity.label || entity.data || '',
2527
+ data: entity.data
2528
+ };
2529
+ });
2530
+ }
2531
+ catch (error) {
2532
+ console.error('Error in _getItemsByTimeWindow:', error);
2533
+ return [];
2534
+ }
2296
2535
  }
2297
2536
  async _calculateTemporalMetrics(cluster, items, timeField) {
2298
2537
  // Calculate temporal characteristics of the cluster
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulcraft/brainy",
3
- "version": "3.25.0",
3
+ "version": "3.25.2",
4
4
  "description": "Universal Knowledge Protocol™ - World's first Triple Intelligence database unifying vector, graph, and document search in one API. 31 nouns × 40 verbs for infinite expressiveness.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",