@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 +94 -5
- package/dist/brainy.js +135 -31
- package/dist/importers/SmartExcelImporter.d.ts +18 -0
- package/dist/importers/SmartExcelImporter.js +60 -2
- package/dist/importers/VFSStructureGenerator.d.ts +3 -0
- package/dist/importers/VFSStructureGenerator.js +13 -5
- package/dist/types/brainy.types.d.ts +14 -0
- package/dist/vfs/VirtualFileSystem.js +11 -5
- package/package.json +1 -1
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
|
-
* //
|
|
419
|
+
* // NEW in v4.3.0: Access flattened fields directly
|
|
375
420
|
* for (const result of results) {
|
|
376
|
-
* console.log(`
|
|
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
|
-
* @
|
|
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
|
-
* //
|
|
563
|
+
* // NEW in v4.3.0: Access flattened fields
|
|
504
564
|
* for (const result of similarDocs) {
|
|
505
|
-
* console.log(`
|
|
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,
|
|
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
|
|
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
|
-
* //
|
|
894
|
+
* // NEW in v4.3.0: Access flattened fields directly
|
|
819
895
|
* for (const result of results) {
|
|
820
|
-
* console.log(`
|
|
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
|
-
* @
|
|
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
|
-
* //
|
|
1242
|
+
* // NEW in v4.3.0: Access flattened fields
|
|
1164
1243
|
* for (const result of similarDocs) {
|
|
1165
|
-
* console.log(`
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
|
35
|
+
// Check if already initialized
|
|
28
36
|
await this.vfs.stat('/');
|
|
29
37
|
}
|
|
30
38
|
catch (error) {
|
|
31
|
-
//
|
|
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
|
|
816
|
-
'
|
|
817
|
-
'
|
|
818
|
-
'
|
|
819
|
-
'
|
|
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.
|
|
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",
|