@soulcraft/brainy 4.2.4 → 4.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/brainy.d.ts CHANGED
@@ -76,6 +76,14 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
76
76
  * Add an entity to the database
77
77
  *
78
78
  * @param params - Parameters for adding the entity
79
+ * @param params.data - Content to embed and store (required)
80
+ * @param params.type - NounType classification (required)
81
+ * @param params.metadata - Custom metadata object
82
+ * @param params.id - Custom ID (auto-generated if not provided)
83
+ * @param params.vector - Pre-computed embedding vector
84
+ * @param params.service - Service name for multi-tenancy
85
+ * @param params.confidence - Type classification confidence (0-1) *New in v4.3.0*
86
+ * @param params.weight - Entity importance/salience (0-1) *New in v4.3.0*
79
87
  * @returns Promise that resolves to the entity ID
80
88
  *
81
89
  * @example Basic entity creation
@@ -88,6 +96,17 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
88
96
  * console.log(`Created entity: ${id}`)
89
97
  * ```
90
98
  *
99
+ * @example Adding with confidence and weight (New in v4.3.0)
100
+ * ```typescript
101
+ * const id = await brain.add({
102
+ * data: "Machine learning model for sentiment analysis",
103
+ * type: NounType.Concept,
104
+ * metadata: { accuracy: 0.95, version: "2.1" },
105
+ * confidence: 0.92, // High confidence in Concept classification
106
+ * weight: 0.85 // High importance entity
107
+ * })
108
+ * ```
109
+ *
91
110
  * @example Adding with custom ID
92
111
  * ```typescript
93
112
  * const customId = await brain.add({
@@ -126,6 +145,11 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
126
145
  * @param id - The unique identifier of the entity to retrieve
127
146
  * @returns Promise that resolves to the entity if found, null if not found
128
147
  *
148
+ * **Entity includes (v4.3.0):**
149
+ * - `confidence` - Type classification confidence (0-1) if set
150
+ * - `weight` - Entity importance/salience (0-1) if set
151
+ * - All standard fields: id, type, data, metadata, vector, timestamps
152
+ *
129
153
  * @example
130
154
  * // Basic entity retrieval
131
155
  * const entity = await brainy.get('user-123')
@@ -137,6 +161,15 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
137
161
  * }
138
162
  *
139
163
  * @example
164
+ * // Accessing confidence and weight (New in v4.3.0)
165
+ * const entity = await brainy.get('concept-456')
166
+ * if (entity) {
167
+ * console.log(`Type: ${entity.type}`)
168
+ * console.log(`Confidence: ${entity.confidence ?? 'N/A'}`)
169
+ * console.log(`Weight: ${entity.weight ?? 'N/A'}`)
170
+ * }
171
+ *
172
+ * @example
140
173
  * // Working with typed entities
141
174
  * interface User {
142
175
  * name: string
@@ -192,6 +225,11 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
192
225
  * }
193
226
  */
194
227
  get(id: string): Promise<Entity<T> | null>;
228
+ /**
229
+ * Create a flattened Result object from entity
230
+ * Flattens commonly-used entity fields to top level for convenience
231
+ */
232
+ private createResult;
195
233
  /**
196
234
  * Convert a noun from storage to an entity
197
235
  */
@@ -353,6 +391,13 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
353
391
  * @param query - Natural language string or structured FindParams object
354
392
  * @returns Promise that resolves to array of search results with scores
355
393
  *
394
+ * **Result Structure (v4.3.0):**
395
+ * Each result includes flattened entity fields for convenient access:
396
+ * - `metadata`, `type`, `data` - Direct access (flattened from entity)
397
+ * - `confidence`, `weight` - Entity confidence/importance (if set)
398
+ * - `entity` - Full Entity object (backward compatible)
399
+ * - `score` - Search relevance score (0-1)
400
+ *
356
401
  * @example
357
402
  * // Natural language queries (most common)
358
403
  * const results = await brainy.find('users who work on AI projects')
@@ -371,11 +416,18 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
371
416
  * }
372
417
  * })
373
418
  *
374
- * // Process results
419
+ * // NEW in v4.3.0: Access flattened fields directly
375
420
  * for (const result of results) {
376
- * console.log(`Found: ${result.entity.data} (score: ${result.score})`)
421
+ * console.log(`Score: ${result.score}`)
422
+ * console.log(`Type: ${result.type}`) // Flattened!
423
+ * console.log(`Metadata:`, result.metadata) // Flattened!
424
+ * console.log(`Confidence: ${result.confidence ?? 'N/A'}`) // Flattened!
425
+ * console.log(`Weight: ${result.weight ?? 'N/A'}`) // Flattened!
377
426
  * }
378
427
  *
428
+ * // Backward compatible: Nested access still works
429
+ * console.log(result.entity.data) // Also works
430
+ *
379
431
  * @example
380
432
  * // Metadata-only filtering (no vector search)
381
433
  * const activeUsers = await brainy.find({
@@ -491,7 +543,15 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
491
543
  * Find similar entities using vector similarity
492
544
  *
493
545
  * @param params - Parameters specifying the target for similarity search
494
- * @returns Promise that resolves to array of similar entities with similarity scores
546
+ * @param params.to - Entity ID, Entity object, or Vector to find similar to (required)
547
+ * @param params.limit - Maximum results (default: 10)
548
+ * @param params.threshold - Minimum similarity (0-1)
549
+ * @param params.type - Filter by NounType(s)
550
+ * @param params.where - Metadata filters
551
+ * @returns Promise that resolves to array of Result objects with similarity scores (same structure as find())
552
+ *
553
+ * **Returns (v4.3.0):**
554
+ * Same Result structure as find() with flattened fields for convenient access
495
555
  *
496
556
  * @example
497
557
  * // Find entities similar to a specific entity by ID
@@ -500,9 +560,12 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
500
560
  * limit: 10
501
561
  * })
502
562
  *
503
- * // Process similarity results
563
+ * // NEW in v4.3.0: Access flattened fields
504
564
  * for (const result of similarDocs) {
505
- * console.log(`Similar entity: ${result.entity.data} (similarity: ${result.score})`)
565
+ * console.log(`Similarity: ${result.score}`)
566
+ * console.log(`Type: ${result.type}`) // Flattened!
567
+ * console.log(`Metadata:`, result.metadata) // Flattened!
568
+ * console.log(`Confidence: ${result.confidence ?? 'N/A'}`) // Flattened!
506
569
  * }
507
570
  *
508
571
  * @example
@@ -799,6 +862,32 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
799
862
  }): Promise<import("./import/ImportCoordinator.js").ImportResult>;
800
863
  /**
801
864
  * Virtual File System API - Knowledge Operating System
865
+ *
866
+ * Returns a cached VFS instance. You must call vfs.init() before use:
867
+ *
868
+ * @example After import
869
+ * ```typescript
870
+ * await brain.import('./data.xlsx', { vfsPath: '/imports/data' })
871
+ *
872
+ * const vfs = brain.vfs()
873
+ * await vfs.init() // Required! (safe to call multiple times)
874
+ * const files = await vfs.readdir('/imports/data')
875
+ * ```
876
+ *
877
+ * @example Direct VFS usage
878
+ * ```typescript
879
+ * const vfs = brain.vfs()
880
+ * await vfs.init() // Always required before first use
881
+ * await vfs.writeFile('/docs/readme.md', 'Hello World')
882
+ * const content = await vfs.readFile('/docs/readme.md')
883
+ * ```
884
+ *
885
+ * **Note:** brain.import() automatically initializes the VFS, so after
886
+ * an import you can call vfs.init() again (it's idempotent) and immediately
887
+ * query the imported files.
888
+ *
889
+ * **Pattern:** The VFS instance is cached, so multiple calls to brain.vfs()
890
+ * return the same instance. This ensures import and user code share state.
802
891
  */
803
892
  vfs(): VirtualFileSystem;
804
893
  /**
package/dist/brainy.js CHANGED
@@ -205,6 +205,14 @@ export class Brainy {
205
205
  * Add an entity to the database
206
206
  *
207
207
  * @param params - Parameters for adding the entity
208
+ * @param params.data - Content to embed and store (required)
209
+ * @param params.type - NounType classification (required)
210
+ * @param params.metadata - Custom metadata object
211
+ * @param params.id - Custom ID (auto-generated if not provided)
212
+ * @param params.vector - Pre-computed embedding vector
213
+ * @param params.service - Service name for multi-tenancy
214
+ * @param params.confidence - Type classification confidence (0-1) *New in v4.3.0*
215
+ * @param params.weight - Entity importance/salience (0-1) *New in v4.3.0*
208
216
  * @returns Promise that resolves to the entity ID
209
217
  *
210
218
  * @example Basic entity creation
@@ -217,6 +225,17 @@ export class Brainy {
217
225
  * console.log(`Created entity: ${id}`)
218
226
  * ```
219
227
  *
228
+ * @example Adding with confidence and weight (New in v4.3.0)
229
+ * ```typescript
230
+ * const id = await brain.add({
231
+ * data: "Machine learning model for sentiment analysis",
232
+ * type: NounType.Concept,
233
+ * metadata: { accuracy: 0.95, version: "2.1" },
234
+ * confidence: 0.92, // High confidence in Concept classification
235
+ * weight: 0.85 // High importance entity
236
+ * })
237
+ * ```
238
+ *
220
239
  * @example Adding with custom ID
221
240
  * ```typescript
222
241
  * const customId = await brain.add({
@@ -280,7 +299,10 @@ export class Brainy {
280
299
  _data: params.data, // Store the raw data in metadata
281
300
  noun: params.type,
282
301
  service: params.service,
283
- createdAt: Date.now()
302
+ createdAt: Date.now(),
303
+ // Preserve confidence and weight if provided
304
+ ...(params.confidence !== undefined && { confidence: params.confidence }),
305
+ ...(params.weight !== undefined && { weight: params.weight })
284
306
  };
285
307
  // v4.0.0: Save vector and metadata separately
286
308
  await this.storage.saveNoun({
@@ -301,6 +323,11 @@ export class Brainy {
301
323
  * @param id - The unique identifier of the entity to retrieve
302
324
  * @returns Promise that resolves to the entity if found, null if not found
303
325
  *
326
+ * **Entity includes (v4.3.0):**
327
+ * - `confidence` - Type classification confidence (0-1) if set
328
+ * - `weight` - Entity importance/salience (0-1) if set
329
+ * - All standard fields: id, type, data, metadata, vector, timestamps
330
+ *
304
331
  * @example
305
332
  * // Basic entity retrieval
306
333
  * const entity = await brainy.get('user-123')
@@ -312,6 +339,15 @@ export class Brainy {
312
339
  * }
313
340
  *
314
341
  * @example
342
+ * // Accessing confidence and weight (New in v4.3.0)
343
+ * const entity = await brainy.get('concept-456')
344
+ * if (entity) {
345
+ * console.log(`Type: ${entity.type}`)
346
+ * console.log(`Confidence: ${entity.confidence ?? 'N/A'}`)
347
+ * console.log(`Weight: ${entity.weight ?? 'N/A'}`)
348
+ * }
349
+ *
350
+ * @example
315
351
  * // Working with typed entities
316
352
  * interface User {
317
353
  * name: string
@@ -378,12 +414,34 @@ export class Brainy {
378
414
  return this.convertNounToEntity(noun);
379
415
  });
380
416
  }
417
+ /**
418
+ * Create a flattened Result object from entity
419
+ * Flattens commonly-used entity fields to top level for convenience
420
+ */
421
+ createResult(id, score, entity, explanation) {
422
+ return {
423
+ id,
424
+ score,
425
+ // Flatten common entity fields to top level
426
+ type: entity.type,
427
+ metadata: entity.metadata,
428
+ data: entity.data,
429
+ confidence: entity.confidence,
430
+ weight: entity.weight,
431
+ // Preserve full entity for backward compatibility
432
+ entity,
433
+ // Optional score explanation
434
+ ...(explanation && { explanation })
435
+ };
436
+ }
381
437
  /**
382
438
  * Convert a noun from storage to an entity
383
439
  */
384
440
  async convertNounToEntity(noun) {
385
441
  // Extract metadata - separate user metadata from system metadata
386
- const { noun: nounType, service, createdAt, updatedAt, _data, ...userMetadata } = noun.metadata || {};
442
+ const { noun: nounType, service, createdAt, updatedAt, _data, confidence, // Entity confidence score (0-1)
443
+ weight, // Entity importance/salience (0-1)
444
+ ...userMetadata } = noun.metadata || {};
387
445
  const entity = {
388
446
  id: noun.id,
389
447
  vector: noun.vector,
@@ -393,10 +451,16 @@ export class Brainy {
393
451
  createdAt: createdAt || Date.now(),
394
452
  updatedAt: updatedAt
395
453
  };
396
- // Only add data field if it exists
454
+ // Only add optional fields if they exist
397
455
  if (_data !== undefined) {
398
456
  entity.data = _data;
399
457
  }
458
+ if (confidence !== undefined) {
459
+ entity.confidence = confidence;
460
+ }
461
+ if (weight !== undefined) {
462
+ entity.weight = weight;
463
+ }
400
464
  return entity;
401
465
  }
402
466
  /**
@@ -444,7 +508,12 @@ export class Brainy {
444
508
  noun: params.type || existing.type,
445
509
  service: existing.service,
446
510
  createdAt: existing.createdAt,
447
- updatedAt: Date.now()
511
+ updatedAt: Date.now(),
512
+ // Update confidence and weight if provided, otherwise preserve existing
513
+ ...(params.confidence !== undefined && { confidence: params.confidence }),
514
+ ...(params.weight !== undefined && { weight: params.weight }),
515
+ ...(params.confidence === undefined && existing.confidence !== undefined && { confidence: existing.confidence }),
516
+ ...(params.weight === undefined && existing.weight !== undefined && { weight: existing.weight })
448
517
  };
449
518
  // v4.0.0: Save vector and metadata separately
450
519
  await this.storage.saveNoun({
@@ -797,6 +866,13 @@ export class Brainy {
797
866
  * @param query - Natural language string or structured FindParams object
798
867
  * @returns Promise that resolves to array of search results with scores
799
868
  *
869
+ * **Result Structure (v4.3.0):**
870
+ * Each result includes flattened entity fields for convenient access:
871
+ * - `metadata`, `type`, `data` - Direct access (flattened from entity)
872
+ * - `confidence`, `weight` - Entity confidence/importance (if set)
873
+ * - `entity` - Full Entity object (backward compatible)
874
+ * - `score` - Search relevance score (0-1)
875
+ *
800
876
  * @example
801
877
  * // Natural language queries (most common)
802
878
  * const results = await brainy.find('users who work on AI projects')
@@ -815,11 +891,18 @@ export class Brainy {
815
891
  * }
816
892
  * })
817
893
  *
818
- * // Process results
894
+ * // NEW in v4.3.0: Access flattened fields directly
819
895
  * for (const result of results) {
820
- * console.log(`Found: ${result.entity.data} (score: ${result.score})`)
896
+ * console.log(`Score: ${result.score}`)
897
+ * console.log(`Type: ${result.type}`) // Flattened!
898
+ * console.log(`Metadata:`, result.metadata) // Flattened!
899
+ * console.log(`Confidence: ${result.confidence ?? 'N/A'}`) // Flattened!
900
+ * console.log(`Weight: ${result.weight ?? 'N/A'}`) // Flattened!
821
901
  * }
822
902
  *
903
+ * // Backward compatible: Nested access still works
904
+ * console.log(result.entity.data) // Also works
905
+ *
823
906
  * @example
824
907
  * // Metadata-only filtering (no vector search)
825
908
  * const activeUsers = await brainy.find({
@@ -996,11 +1079,7 @@ export class Brainy {
996
1079
  for (const id of pageIds) {
997
1080
  const entity = await this.get(id);
998
1081
  if (entity) {
999
- results.push({
1000
- id,
1001
- score: 1.0, // All metadata-filtered results equally relevant
1002
- entity
1003
- });
1082
+ results.push(this.createResult(id, 1.0, entity));
1004
1083
  }
1005
1084
  }
1006
1085
  return results;
@@ -1016,11 +1095,7 @@ export class Brainy {
1016
1095
  const noun = storageResults.items[i];
1017
1096
  if (noun) {
1018
1097
  const entity = await this.convertNounToEntity(noun);
1019
- results.push({
1020
- id: noun.id,
1021
- score: 1.0, // All results equally relevant for empty query
1022
- entity
1023
- });
1098
+ results.push(this.createResult(noun.id, 1.0, entity));
1024
1099
  }
1025
1100
  }
1026
1101
  return results;
@@ -1114,11 +1189,7 @@ export class Brainy {
1114
1189
  for (const id of pageIds) {
1115
1190
  const entity = await this.get(id);
1116
1191
  if (entity) {
1117
- results.push({
1118
- id,
1119
- score: 1.0, // All metadata matches are equally relevant
1120
- entity: entity
1121
- });
1192
+ results.push(this.createResult(id, 1.0, entity));
1122
1193
  }
1123
1194
  }
1124
1195
  // Early return for metadata-only queries with pagination applied
@@ -1151,7 +1222,15 @@ export class Brainy {
1151
1222
  * Find similar entities using vector similarity
1152
1223
  *
1153
1224
  * @param params - Parameters specifying the target for similarity search
1154
- * @returns Promise that resolves to array of similar entities with similarity scores
1225
+ * @param params.to - Entity ID, Entity object, or Vector to find similar to (required)
1226
+ * @param params.limit - Maximum results (default: 10)
1227
+ * @param params.threshold - Minimum similarity (0-1)
1228
+ * @param params.type - Filter by NounType(s)
1229
+ * @param params.where - Metadata filters
1230
+ * @returns Promise that resolves to array of Result objects with similarity scores (same structure as find())
1231
+ *
1232
+ * **Returns (v4.3.0):**
1233
+ * Same Result structure as find() with flattened fields for convenient access
1155
1234
  *
1156
1235
  * @example
1157
1236
  * // Find entities similar to a specific entity by ID
@@ -1160,9 +1239,12 @@ export class Brainy {
1160
1239
  * limit: 10
1161
1240
  * })
1162
1241
  *
1163
- * // Process similarity results
1242
+ * // NEW in v4.3.0: Access flattened fields
1164
1243
  * for (const result of similarDocs) {
1165
- * console.log(`Similar entity: ${result.entity.data} (similarity: ${result.score})`)
1244
+ * console.log(`Similarity: ${result.score}`)
1245
+ * console.log(`Type: ${result.type}`) // Flattened!
1246
+ * console.log(`Metadata:`, result.metadata) // Flattened!
1247
+ * console.log(`Confidence: ${result.confidence ?? 'N/A'}`) // Flattened!
1166
1248
  * }
1167
1249
  *
1168
1250
  * @example
@@ -1688,6 +1770,32 @@ export class Brainy {
1688
1770
  }
1689
1771
  /**
1690
1772
  * Virtual File System API - Knowledge Operating System
1773
+ *
1774
+ * Returns a cached VFS instance. You must call vfs.init() before use:
1775
+ *
1776
+ * @example After import
1777
+ * ```typescript
1778
+ * await brain.import('./data.xlsx', { vfsPath: '/imports/data' })
1779
+ *
1780
+ * const vfs = brain.vfs()
1781
+ * await vfs.init() // Required! (safe to call multiple times)
1782
+ * const files = await vfs.readdir('/imports/data')
1783
+ * ```
1784
+ *
1785
+ * @example Direct VFS usage
1786
+ * ```typescript
1787
+ * const vfs = brain.vfs()
1788
+ * await vfs.init() // Always required before first use
1789
+ * await vfs.writeFile('/docs/readme.md', 'Hello World')
1790
+ * const content = await vfs.readFile('/docs/readme.md')
1791
+ * ```
1792
+ *
1793
+ * **Note:** brain.import() automatically initializes the VFS, so after
1794
+ * an import you can call vfs.init() again (it's idempotent) and immediately
1795
+ * query the imported files.
1796
+ *
1797
+ * **Pattern:** The VFS instance is cached, so multiple calls to brain.vfs()
1798
+ * return the same instance. This ensures import and user code share state.
1691
1799
  */
1692
1800
  vfs() {
1693
1801
  if (!this._vfs) {
@@ -2187,7 +2295,7 @@ export class Brainy {
2187
2295
  const entity = await this.get(id);
2188
2296
  if (entity) {
2189
2297
  const score = Math.max(0, Math.min(1, 1 / (1 + distance)));
2190
- results.push({ id, score, entity });
2298
+ results.push(this.createResult(id, score, entity));
2191
2299
  }
2192
2300
  }
2193
2301
  return results;
@@ -2211,7 +2319,7 @@ export class Brainy {
2211
2319
  if (score >= (params.near.threshold || 0.7)) {
2212
2320
  const entity = await this.get(id);
2213
2321
  if (entity) {
2214
- results.push({ id, score, entity });
2322
+ results.push(this.createResult(id, score, entity));
2215
2323
  }
2216
2324
  }
2217
2325
  }
@@ -2244,11 +2352,7 @@ export class Brainy {
2244
2352
  for (const id of connectedIds) {
2245
2353
  const entity = await this.get(id);
2246
2354
  if (entity) {
2247
- results.push({
2248
- id,
2249
- score: 1.0,
2250
- entity
2251
- });
2355
+ results.push(this.createResult(id, 1.0, entity));
2252
2356
  }
2253
2357
  }
2254
2358
  return results;
@@ -129,6 +129,24 @@ export declare class SmartExcelImporter {
129
129
  * Map type string to NounType
130
130
  */
131
131
  private mapTypeString;
132
+ /**
133
+ * Infer entity type from Excel sheet name
134
+ *
135
+ * Uses common naming patterns to suggest appropriate entity types:
136
+ * - "Characters", "People", "Humans" → Person
137
+ * - "Places", "Locations" → Location
138
+ * - "Terms", "Concepts", "Glossary" → Concept
139
+ * - etc.
140
+ *
141
+ * @param sheetName - Excel sheet name
142
+ * @returns Inferred NounType or null if no match
143
+ *
144
+ * @example
145
+ * inferTypeFromSheetName("Characters") // → NounType.Person
146
+ * inferTypeFromSheetName("Places") // → NounType.Location
147
+ * inferTypeFromSheetName("Animals") // → null (no semantic hint)
148
+ */
149
+ private inferTypeFromSheetName;
132
150
  /**
133
151
  * Infer relationship type from context using SmartRelationshipExtractor
134
152
  */
@@ -107,10 +107,16 @@ export class SmartExcelImporter {
107
107
  ? this.brain.extractConcepts(definition, { limit: 10 }).catch(() => [])
108
108
  : Promise.resolve([])
109
109
  ]);
110
- // Determine main entity type
110
+ // Determine main entity type with priority order:
111
+ // 1. Explicit "Type" column (highest priority - user specified)
112
+ // 2. Sheet name inference (NEW - semantic hint from Excel structure)
113
+ // 3. AI extraction from related entities
114
+ // 4. Default to Thing (fallback)
115
+ const sheetTypeHint = this.inferTypeFromSheetName(row._sheet || '');
111
116
  const mainEntityType = type ?
112
117
  this.mapTypeString(type) :
113
- (relatedEntities.length > 0 ? relatedEntities[0].type : NounType.Thing);
118
+ sheetTypeHint ||
119
+ (relatedEntities.length > 0 ? relatedEntities[0].type : NounType.Thing);
114
120
  // Generate entity ID
115
121
  const entityId = this.generateEntityId(term);
116
122
  // Create main entity
@@ -297,6 +303,58 @@ export class SmartExcelImporter {
297
303
  };
298
304
  return mapping[normalized] || NounType.Thing;
299
305
  }
306
+ /**
307
+ * Infer entity type from Excel sheet name
308
+ *
309
+ * Uses common naming patterns to suggest appropriate entity types:
310
+ * - "Characters", "People", "Humans" → Person
311
+ * - "Places", "Locations" → Location
312
+ * - "Terms", "Concepts", "Glossary" → Concept
313
+ * - etc.
314
+ *
315
+ * @param sheetName - Excel sheet name
316
+ * @returns Inferred NounType or null if no match
317
+ *
318
+ * @example
319
+ * inferTypeFromSheetName("Characters") // → NounType.Person
320
+ * inferTypeFromSheetName("Places") // → NounType.Location
321
+ * inferTypeFromSheetName("Animals") // → null (no semantic hint)
322
+ */
323
+ inferTypeFromSheetName(sheetName) {
324
+ if (!sheetName)
325
+ return null;
326
+ const normalized = sheetName.toLowerCase();
327
+ // Person types: characters, people, humans, individuals
328
+ if (normalized.match(/character|people|person|human|individual|npc|cast/)) {
329
+ return NounType.Person;
330
+ }
331
+ // Location types: places, locations, areas, regions
332
+ if (normalized.match(/place|location|area|region|zone|geography|map|world/)) {
333
+ return NounType.Location;
334
+ }
335
+ // Concept types: terms, concepts, ideas, glossary
336
+ if (normalized.match(/term|concept|idea|definition|glossary|vocabulary|lexicon/)) {
337
+ return NounType.Concept;
338
+ }
339
+ // Organization types: groups, factions, companies
340
+ if (normalized.match(/organization|company|group|faction|tribe|guild|clan|corp/)) {
341
+ return NounType.Organization;
342
+ }
343
+ // Event types: events, occurrences, happenings
344
+ if (normalized.match(/event|occurrence|happening|battle|encounter|scene/)) {
345
+ return NounType.Event;
346
+ }
347
+ // Product types: items, equipment, gear
348
+ if (normalized.match(/item|product|equipment|gear|weapon|armor|artifact|treasure/)) {
349
+ return NounType.Product;
350
+ }
351
+ // Project types: quests, missions, campaigns
352
+ if (normalized.match(/project|quest|mission|campaign|task/)) {
353
+ return NounType.Project;
354
+ }
355
+ // No semantic match found - return null to continue to next type determination method
356
+ return null;
357
+ }
300
358
  /**
301
359
  * Infer relationship type from context using SmartRelationshipExtractor
302
360
  */
@@ -53,6 +53,9 @@ export declare class VFSStructureGenerator {
53
53
  constructor(brain: Brainy);
54
54
  /**
55
55
  * Initialize the generator
56
+ *
57
+ * CRITICAL: Gets brain's VFS instance and initializes it if needed.
58
+ * This ensures that after import, brain.vfs() returns an initialized instance.
56
59
  */
57
60
  init(): Promise<void>;
58
61
  /**
@@ -8,7 +8,6 @@
8
8
  *
9
9
  * NO MOCKS - Production-ready implementation
10
10
  */
11
- import { VirtualFileSystem } from '../vfs/VirtualFileSystem.js';
12
11
  import { NounType } from '../types/graphTypes.js';
13
12
  /**
14
13
  * VFSStructureGenerator - Organizes imported data into VFS
@@ -16,19 +15,28 @@ import { NounType } from '../types/graphTypes.js';
16
15
  export class VFSStructureGenerator {
17
16
  constructor(brain) {
18
17
  this.brain = brain;
19
- this.vfs = new VirtualFileSystem(brain);
18
+ // CRITICAL FIX: Use brain.vfs() instead of creating separate instance
19
+ // This ensures VFSStructureGenerator and user code share the same VFS instance
20
+ // Before: Created separate instance that wasn't accessible to users
21
+ // After: Uses brain's cached instance, making VFS queryable after import
20
22
  }
21
23
  /**
22
24
  * Initialize the generator
25
+ *
26
+ * CRITICAL: Gets brain's VFS instance and initializes it if needed.
27
+ * This ensures that after import, brain.vfs() returns an initialized instance.
23
28
  */
24
29
  async init() {
25
- // Always ensure VFS is initialized
30
+ // Get brain's cached VFS instance (creates if doesn't exist)
31
+ this.vfs = this.brain.vfs();
32
+ // Initialize if not already initialized
33
+ // VFS.init() is idempotent (safe to call multiple times)
26
34
  try {
27
- // Check if VFS is initialized by trying to access root
35
+ // Check if already initialized
28
36
  await this.vfs.stat('/');
29
37
  }
30
38
  catch (error) {
31
- // VFS not initialized, initialize it
39
+ // Not initialized, initialize now
32
40
  await this.vfs.init();
33
41
  }
34
42
  }
@@ -18,6 +18,8 @@ export interface Entity<T = any> {
18
18
  createdAt: number;
19
19
  updatedAt?: number;
20
20
  createdBy?: string;
21
+ confidence?: number;
22
+ weight?: number;
21
23
  }
22
24
  /**
23
25
  * Relation representation (replaces GraphVerb)
@@ -50,10 +52,18 @@ export interface RelationEvidence {
50
52
  }
51
53
  /**
52
54
  * Search result with similarity score
55
+ *
56
+ * Flattens commonly-used entity fields to top level for convenience,
57
+ * while preserving full entity in 'entity' field for backward compatibility.
53
58
  */
54
59
  export interface Result<T = any> {
55
60
  id: string;
56
61
  score: number;
62
+ type?: NounType;
63
+ metadata?: T;
64
+ data?: any;
65
+ confidence?: number;
66
+ weight?: number;
57
67
  entity: Entity<T>;
58
68
  explanation?: ScoreExplanation;
59
69
  }
@@ -77,6 +87,8 @@ export interface AddParams<T = any> {
77
87
  id?: string;
78
88
  vector?: Vector;
79
89
  service?: string;
90
+ confidence?: number;
91
+ weight?: number;
80
92
  }
81
93
  /**
82
94
  * Parameters for updating entities
@@ -88,6 +100,8 @@ export interface UpdateParams<T = any> {
88
100
  metadata?: Partial<T>;
89
101
  merge?: boolean;
90
102
  vector?: Vector;
103
+ confidence?: number;
104
+ weight?: number;
91
105
  }
92
106
  /**
93
107
  * Parameters for creating relationships
@@ -812,11 +812,17 @@ export class VirtualFileSystem {
812
812
  // ============= Helper Methods =============
813
813
  async ensureInitialized() {
814
814
  if (!this.initialized) {
815
- throw new Error('VFS not initialized. You must call await vfs.init() after getting the VFS instance.\n' +
816
- 'Example:\n' +
817
- ' const vfs = brain.vfs() // Note: vfs() is a method, not a property\n' +
818
- ' await vfs.init() // This creates the root directory\n' +
819
- 'See docs: https://github.com/Brainy-Technologies/brainy/blob/main/docs/vfs/QUICK_START.md');
815
+ throw new VFSError(VFSErrorCode.EINVAL, 'VFS not initialized. Call await vfs.init() before using VFS operations.\n\n' +
816
+ '✅ After brain.import():\n' +
817
+ ' await brain.import(file, { vfsPath: "/imports/data" })\n' +
818
+ ' const vfs = brain.vfs()\n' +
819
+ ' await vfs.init() // ← Required! Safe to call multiple times\n' +
820
+ ' const files = await vfs.readdir("/imports/data")\n\n' +
821
+ '✅ Direct VFS usage:\n' +
822
+ ' const vfs = brain.vfs()\n' +
823
+ ' await vfs.init() // ← Always required before first use\n' +
824
+ ' await vfs.writeFile("/docs/readme.md", "Hello")\n\n' +
825
+ '📖 Docs: https://github.com/soulcraftlabs/brainy/blob/main/docs/vfs/QUICK_START.md', '<unknown>', 'VFS');
820
826
  }
821
827
  }
822
828
  async ensureDirectory(path) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulcraft/brainy",
3
- "version": "4.2.4",
3
+ "version": "4.3.1",
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",