@soulcraft/brainy 4.8.6 β 4.9.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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,76 @@
|
|
|
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
|
+
## [4.9.1](https://github.com/soulcraftlabs/brainy/compare/v4.9.0...v4.9.1) (2025-10-29)
|
|
6
|
+
|
|
7
|
+
### π Documentation
|
|
8
|
+
|
|
9
|
+
* **vfs**: Fix NO FAKE CODE policy violations in VFS documentation
|
|
10
|
+
- **Removed**: 9 undocumented feature sections (~242 lines) from VFS docs
|
|
11
|
+
- Version History, Distributed Filesystem, AI Auto-Organization
|
|
12
|
+
- Security & Permissions, Smart Collections, Express.js middleware
|
|
13
|
+
- VSCode extension, Production Metrics, Backup & Recovery
|
|
14
|
+
- **Added**: Status labels (β
Production, β οΈ Beta, π§ͺ Experimental) to all VFS features
|
|
15
|
+
- **Updated**: Performance claims with MEASURED vs PROJECTED labels
|
|
16
|
+
- **Created**: `docs/vfs/ROADMAP.md` for planned features (preserves vision without misleading)
|
|
17
|
+
- **Fixed**: Storage adapter list to show only 8 built-in adapters (removed Redis, PostgreSQL, ChromaDB)
|
|
18
|
+
- **Impact**: VFS documentation now 100% compliant with NO FAKE CODE policy
|
|
19
|
+
|
|
20
|
+
### Files Modified
|
|
21
|
+
- `docs/vfs/README.md`: Removed 9 fake feature sections, updated performance claims
|
|
22
|
+
- `docs/vfs/SEMANTIC_VFS.md`: Added status labels, updated scale testing tables
|
|
23
|
+
- `docs/vfs/VFS_API_GUIDE.md`: Fixed storage adapter compatibility list
|
|
24
|
+
- `docs/vfs/ROADMAP.md`: New file organizing planned features by version
|
|
25
|
+
|
|
26
|
+
## [4.9.0](https://github.com/soulcraftlabs/brainy/compare/v4.8.6...v4.9.0) (2025-10-28)
|
|
27
|
+
|
|
28
|
+
**UNIVERSAL RELATIONSHIP EXTRACTION - Knowledge Graph Builder**
|
|
29
|
+
|
|
30
|
+
This release transforms Brainy imports from entity extractors into true knowledge graph builders with full provenance tracking and semantic relationship enhancement.
|
|
31
|
+
|
|
32
|
+
### β¨ Features
|
|
33
|
+
|
|
34
|
+
* **import**: Universal relationship extraction with provenance tracking
|
|
35
|
+
- **Document Entity Creation**: Every import now creates a `document` entity representing the source file
|
|
36
|
+
- **Provenance Relationships**: Full data lineage with `document β entity` relationships for every imported entity
|
|
37
|
+
- **Relationship Type Metadata**: All relationships tagged as `vfs`, `semantic`, or `provenance` for filtering
|
|
38
|
+
- **Enhanced Column Detection**: 7 relationship types (vs 1 previously) - Location, Owner, Creator, Uses, Member, Friend, Related
|
|
39
|
+
- **Type-Based Inference**: Smart relationship classification based on entity types and context analysis
|
|
40
|
+
- **Impact**: Workshop import now creates ~3,900 relationships (vs 581), with 5-20+ connections per entity
|
|
41
|
+
|
|
42
|
+
* **import**: New configuration option `createProvenanceLinks` (defaults to `true`)
|
|
43
|
+
- Enables/disables provenance relationship creation
|
|
44
|
+
- Backward compatible - all features opt-in
|
|
45
|
+
|
|
46
|
+
### π Impact
|
|
47
|
+
|
|
48
|
+
**Before v4.9.0:**
|
|
49
|
+
```
|
|
50
|
+
Import: glossary.xlsx (1,149 rows)
|
|
51
|
+
Result: 1,149 entities, 581 relationships (VFS only)
|
|
52
|
+
Graph: Isolated nodes, 0 semantic connections
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**After v4.9.0:**
|
|
56
|
+
```
|
|
57
|
+
Import: glossary.xlsx (1,149 rows)
|
|
58
|
+
Result: 1,150 entities (+ document), ~3,900 relationships
|
|
59
|
+
- 1,149 provenance (document β entity)
|
|
60
|
+
- ~1,500 semantic (entity β entity, diverse types)
|
|
61
|
+
- 581 VFS (directory structure, marked separately)
|
|
62
|
+
Graph: Rich network, 5-20+ connections per entity
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### π§ Technical Details
|
|
66
|
+
|
|
67
|
+
* **Files Modified**: 3 files, 257 insertions(+), 11 deletions(-)
|
|
68
|
+
- `ImportCoordinator.ts`: +175 lines (document entity, provenance, inference)
|
|
69
|
+
- `SmartExcelImporter.ts`: +65 lines (enhanced column patterns)
|
|
70
|
+
- `VirtualFileSystem.ts`: +2 lines (relationship type metadata)
|
|
71
|
+
|
|
72
|
+
* **Universal Support**: Works across ALL 7 import formats (Excel, PDF, CSV, JSON, Markdown, YAML, DOCX)
|
|
73
|
+
* **Backward Compatible**: 100% - all features opt-in, existing imports unchanged
|
|
74
|
+
|
|
5
75
|
### [4.8.6](https://github.com/soulcraftlabs/brainy/compare/v4.8.5...v4.8.6) (2025-10-28)
|
|
6
76
|
|
|
7
77
|
- fix: per-sheet column detection in Excel importer (401443a)
|
|
@@ -44,6 +44,8 @@ export interface ValidImportOptions {
|
|
|
44
44
|
createEntities?: boolean;
|
|
45
45
|
/** Create relationships in knowledge graph */
|
|
46
46
|
createRelationships?: boolean;
|
|
47
|
+
/** Create provenance relationships (document β entity) [v4.9.0] */
|
|
48
|
+
createProvenanceLinks?: boolean;
|
|
47
49
|
/** Preserve source file in VFS */
|
|
48
50
|
preserveSource?: boolean;
|
|
49
51
|
/** Enable neural entity extraction */
|
|
@@ -267,6 +269,7 @@ export declare class ImportCoordinator {
|
|
|
267
269
|
private extract;
|
|
268
270
|
/**
|
|
269
271
|
* Create entities and relationships in knowledge graph
|
|
272
|
+
* v4.9.0: Added sourceInfo parameter for document entity creation
|
|
270
273
|
*/
|
|
271
274
|
private createGraphEntities;
|
|
272
275
|
/**
|
|
@@ -315,4 +318,22 @@ export declare class ImportCoordinator {
|
|
|
315
318
|
* @returns Current optimal flush interval
|
|
316
319
|
*/
|
|
317
320
|
private getProgressiveFlushInterval;
|
|
321
|
+
/**
|
|
322
|
+
* Infer relationship type based on entity types and context
|
|
323
|
+
* v4.9.0: Semantic relationship enhancement
|
|
324
|
+
*
|
|
325
|
+
* @param sourceType - Type of source entity
|
|
326
|
+
* @param targetType - Type of target entity
|
|
327
|
+
* @param context - Optional context string for additional hints
|
|
328
|
+
* @returns Inferred verb type
|
|
329
|
+
*/
|
|
330
|
+
private inferRelationshipType;
|
|
331
|
+
/**
|
|
332
|
+
* Count entities by type for document metadata
|
|
333
|
+
* v4.9.0: Used for document entity statistics
|
|
334
|
+
*
|
|
335
|
+
* @param rows - Extracted rows from import
|
|
336
|
+
* @returns Record of entity type counts
|
|
337
|
+
*/
|
|
338
|
+
private countByType;
|
|
318
339
|
}
|
|
@@ -20,7 +20,7 @@ import { SmartMarkdownImporter } from '../importers/SmartMarkdownImporter.js';
|
|
|
20
20
|
import { SmartYAMLImporter } from '../importers/SmartYAMLImporter.js';
|
|
21
21
|
import { SmartDOCXImporter } from '../importers/SmartDOCXImporter.js';
|
|
22
22
|
import { VFSStructureGenerator } from '../importers/VFSStructureGenerator.js';
|
|
23
|
-
import { NounType } from '../types/graphTypes.js';
|
|
23
|
+
import { NounType, VerbType } from '../types/graphTypes.js';
|
|
24
24
|
import { v4 as uuidv4 } from '../universal/uuid.js';
|
|
25
25
|
import * as fs from 'fs';
|
|
26
26
|
import * as path from 'path';
|
|
@@ -134,7 +134,10 @@ export class ImportCoordinator {
|
|
|
134
134
|
message: 'Creating knowledge graph...'
|
|
135
135
|
});
|
|
136
136
|
// Create entities and relationships in graph
|
|
137
|
-
const graphResult = await this.createGraphEntities(normalizedResult, vfsResult, opts
|
|
137
|
+
const graphResult = await this.createGraphEntities(normalizedResult, vfsResult, opts, {
|
|
138
|
+
sourceFilename: normalizedSource.filename || `import.${detection.format}`,
|
|
139
|
+
format: detection.format
|
|
140
|
+
});
|
|
138
141
|
// Report complete
|
|
139
142
|
options.onProgress?.({
|
|
140
143
|
stage: 'complete',
|
|
@@ -409,8 +412,9 @@ export class ImportCoordinator {
|
|
|
409
412
|
}
|
|
410
413
|
/**
|
|
411
414
|
* Create entities and relationships in knowledge graph
|
|
415
|
+
* v4.9.0: Added sourceInfo parameter for document entity creation
|
|
412
416
|
*/
|
|
413
|
-
async createGraphEntities(extractionResult, vfsResult, options) {
|
|
417
|
+
async createGraphEntities(extractionResult, vfsResult, options, sourceInfo) {
|
|
414
418
|
const entities = [];
|
|
415
419
|
const relationships = [];
|
|
416
420
|
let mergedCount = 0;
|
|
@@ -419,7 +423,14 @@ export class ImportCoordinator {
|
|
|
419
423
|
// Previously: if (!options.createEntities) treated undefined as false
|
|
420
424
|
// Now: Only skip when explicitly set to false
|
|
421
425
|
if (options.createEntities === false) {
|
|
422
|
-
return {
|
|
426
|
+
return {
|
|
427
|
+
entities,
|
|
428
|
+
relationships,
|
|
429
|
+
merged: 0,
|
|
430
|
+
newEntities: 0,
|
|
431
|
+
documentEntity: undefined,
|
|
432
|
+
provenanceCount: 0
|
|
433
|
+
};
|
|
423
434
|
}
|
|
424
435
|
// Extract rows/sections/entities from result (unified across formats)
|
|
425
436
|
const rows = extractionResult.rows || extractionResult.sections || extractionResult.entities || [];
|
|
@@ -444,6 +455,29 @@ export class ImportCoordinator {
|
|
|
444
455
|
` Tip: For large imports, deduplicate manually after import or use smaller batches\n` +
|
|
445
456
|
` Override: Set deduplicationThreshold to force enable (not recommended for >500 entities)`);
|
|
446
457
|
}
|
|
458
|
+
// ============================================
|
|
459
|
+
// v4.9.0: Create document entity for import source
|
|
460
|
+
// ============================================
|
|
461
|
+
let documentEntityId = null;
|
|
462
|
+
let provenanceCount = 0;
|
|
463
|
+
if (sourceInfo && options.createProvenanceLinks !== false) {
|
|
464
|
+
console.log(`π Creating document entity for import source: ${sourceInfo.sourceFilename}`);
|
|
465
|
+
documentEntityId = await this.brain.add({
|
|
466
|
+
data: sourceInfo.sourceFilename,
|
|
467
|
+
type: NounType.Document,
|
|
468
|
+
metadata: {
|
|
469
|
+
name: sourceInfo.sourceFilename,
|
|
470
|
+
sourceFile: sourceInfo.sourceFilename,
|
|
471
|
+
format: sourceInfo.format,
|
|
472
|
+
importedAt: Date.now(),
|
|
473
|
+
importSource: true,
|
|
474
|
+
vfsPath: vfsResult.rootPath,
|
|
475
|
+
totalRows: rows.length,
|
|
476
|
+
byType: this.countByType(rows)
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
console.log(`β
Document entity created: ${documentEntityId}`);
|
|
480
|
+
}
|
|
447
481
|
// Create entities in graph
|
|
448
482
|
for (const row of rows) {
|
|
449
483
|
const entity = row.entity || row;
|
|
@@ -506,6 +540,25 @@ export class ImportCoordinator {
|
|
|
506
540
|
type: entity.type,
|
|
507
541
|
vfsPath: vfsFile?.path
|
|
508
542
|
});
|
|
543
|
+
// ============================================
|
|
544
|
+
// v4.9.0: Create provenance relationship (document β entity)
|
|
545
|
+
// ============================================
|
|
546
|
+
if (documentEntityId && options.createProvenanceLinks !== false) {
|
|
547
|
+
await this.brain.relate({
|
|
548
|
+
from: documentEntityId,
|
|
549
|
+
to: entityId,
|
|
550
|
+
type: VerbType.Contains,
|
|
551
|
+
metadata: {
|
|
552
|
+
relationshipType: 'provenance',
|
|
553
|
+
evidence: `Extracted from ${sourceInfo?.sourceFilename}`,
|
|
554
|
+
sheet: row.sheet,
|
|
555
|
+
rowNumber: row.rowNumber,
|
|
556
|
+
extractedAt: Date.now(),
|
|
557
|
+
format: sourceInfo?.format
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
provenanceCount++;
|
|
561
|
+
}
|
|
509
562
|
// Collect relationships for batch creation
|
|
510
563
|
if (options.createRelationships && row.relationships) {
|
|
511
564
|
for (const rel of row.relationships) {
|
|
@@ -624,14 +677,30 @@ export class ImportCoordinator {
|
|
|
624
677
|
});
|
|
625
678
|
}
|
|
626
679
|
// Batch create all relationships using brain.relateMany() for performance
|
|
680
|
+
// v4.9.0: Enhanced with type-based inference and semantic metadata
|
|
627
681
|
if (options.createRelationships && relationships.length > 0) {
|
|
628
682
|
try {
|
|
629
|
-
const relationshipParams = relationships.map(rel =>
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
683
|
+
const relationshipParams = relationships.map(rel => {
|
|
684
|
+
// Get entity types for inference
|
|
685
|
+
const sourceEntity = entities.find(e => e.id === rel.from);
|
|
686
|
+
const targetEntity = entities.find(e => e.id === rel.to);
|
|
687
|
+
// Infer better relationship type if generic and we have entity types
|
|
688
|
+
let verbType = rel.type;
|
|
689
|
+
if (verbType === VerbType.RelatedTo && sourceEntity && targetEntity) {
|
|
690
|
+
verbType = this.inferRelationshipType(sourceEntity.type, targetEntity.type, rel.metadata?.evidence);
|
|
691
|
+
}
|
|
692
|
+
return {
|
|
693
|
+
from: rel.from,
|
|
694
|
+
to: rel.to,
|
|
695
|
+
type: verbType, // Enhanced type
|
|
696
|
+
metadata: {
|
|
697
|
+
...(rel.metadata || {}),
|
|
698
|
+
relationshipType: 'semantic', // v4.9.0: Distinguish from VFS/provenance
|
|
699
|
+
inferredType: verbType !== rel.type, // Track if type was enhanced
|
|
700
|
+
originalType: rel.type
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
});
|
|
635
704
|
const relationshipIds = await this.brain.relateMany({
|
|
636
705
|
items: relationshipParams,
|
|
637
706
|
parallel: true,
|
|
@@ -666,7 +735,9 @@ export class ImportCoordinator {
|
|
|
666
735
|
entities,
|
|
667
736
|
relationships,
|
|
668
737
|
merged: mergedCount,
|
|
669
|
-
newEntities: newCount
|
|
738
|
+
newEntities: newCount,
|
|
739
|
+
documentEntity: documentEntityId || undefined,
|
|
740
|
+
provenanceCount
|
|
670
741
|
};
|
|
671
742
|
}
|
|
672
743
|
/**
|
|
@@ -908,5 +979,79 @@ ${optionDetails}
|
|
|
908
979
|
return 5000; // Performance-focused interval for large imports
|
|
909
980
|
}
|
|
910
981
|
}
|
|
982
|
+
/**
|
|
983
|
+
* Infer relationship type based on entity types and context
|
|
984
|
+
* v4.9.0: Semantic relationship enhancement
|
|
985
|
+
*
|
|
986
|
+
* @param sourceType - Type of source entity
|
|
987
|
+
* @param targetType - Type of target entity
|
|
988
|
+
* @param context - Optional context string for additional hints
|
|
989
|
+
* @returns Inferred verb type
|
|
990
|
+
*/
|
|
991
|
+
inferRelationshipType(sourceType, targetType, context) {
|
|
992
|
+
// Context-based inference (highest priority)
|
|
993
|
+
if (context) {
|
|
994
|
+
const lowerContext = context.toLowerCase();
|
|
995
|
+
if (lowerContext.includes('live') || lowerContext.includes('reside') || lowerContext.includes('dwell')) {
|
|
996
|
+
return VerbType.LocatedAt;
|
|
997
|
+
}
|
|
998
|
+
if (lowerContext.includes('create') || lowerContext.includes('invent') || lowerContext.includes('make')) {
|
|
999
|
+
return VerbType.Creates;
|
|
1000
|
+
}
|
|
1001
|
+
if (lowerContext.includes('own') || lowerContext.includes('possess') || lowerContext.includes('belong')) {
|
|
1002
|
+
return VerbType.PartOf;
|
|
1003
|
+
}
|
|
1004
|
+
if (lowerContext.includes('work') || lowerContext.includes('collaborate') || lowerContext.includes('team')) {
|
|
1005
|
+
return VerbType.WorksWith;
|
|
1006
|
+
}
|
|
1007
|
+
if (lowerContext.includes('use') || lowerContext.includes('wield') || lowerContext.includes('employ')) {
|
|
1008
|
+
return VerbType.Uses;
|
|
1009
|
+
}
|
|
1010
|
+
if (lowerContext.includes('know') || lowerContext.includes('friend') || lowerContext.includes('ally')) {
|
|
1011
|
+
return VerbType.FriendOf;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
// Type-based inference (fallback)
|
|
1015
|
+
// Sort types for consistent lookup
|
|
1016
|
+
const sortedTypes = [sourceType, targetType].sort();
|
|
1017
|
+
const typeKey = `${sortedTypes[0]}+${sortedTypes[1]}`;
|
|
1018
|
+
const typeMapping = {
|
|
1019
|
+
// Person relationships
|
|
1020
|
+
[`${NounType.Person}+${NounType.Location}`]: VerbType.LocatedAt,
|
|
1021
|
+
[`${NounType.Person}+${NounType.Thing}`]: VerbType.Uses,
|
|
1022
|
+
[`${NounType.Person}+${NounType.Person}`]: VerbType.FriendOf,
|
|
1023
|
+
[`${NounType.Person}+${NounType.Concept}`]: VerbType.RelatedTo,
|
|
1024
|
+
[`${NounType.Person}+${NounType.Event}`]: VerbType.RelatedTo,
|
|
1025
|
+
// Location relationships
|
|
1026
|
+
[`${NounType.Location}+${NounType.Thing}`]: VerbType.Contains,
|
|
1027
|
+
[`${NounType.Location}+${NounType.Concept}`]: VerbType.RelatedTo,
|
|
1028
|
+
[`${NounType.Location}+${NounType.Event}`]: VerbType.LocatedAt,
|
|
1029
|
+
// Thing relationships
|
|
1030
|
+
[`${NounType.Thing}+${NounType.Concept}`]: VerbType.RelatedTo,
|
|
1031
|
+
[`${NounType.Thing}+${NounType.Event}`]: VerbType.RelatedTo,
|
|
1032
|
+
// Concept relationships
|
|
1033
|
+
[`${NounType.Concept}+${NounType.Concept}`]: VerbType.RelatedTo,
|
|
1034
|
+
[`${NounType.Concept}+${NounType.Event}`]: VerbType.RelatedTo,
|
|
1035
|
+
// Event relationships
|
|
1036
|
+
[`${NounType.Event}+${NounType.Event}`]: VerbType.Precedes
|
|
1037
|
+
};
|
|
1038
|
+
return typeMapping[typeKey] || VerbType.RelatedTo;
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Count entities by type for document metadata
|
|
1042
|
+
* v4.9.0: Used for document entity statistics
|
|
1043
|
+
*
|
|
1044
|
+
* @param rows - Extracted rows from import
|
|
1045
|
+
* @returns Record of entity type counts
|
|
1046
|
+
*/
|
|
1047
|
+
countByType(rows) {
|
|
1048
|
+
const counts = {};
|
|
1049
|
+
for (const row of rows) {
|
|
1050
|
+
const entity = row.entity || row;
|
|
1051
|
+
const type = entity.type || NounType.Thing;
|
|
1052
|
+
counts[type] = (counts[type] || 0) + 1;
|
|
1053
|
+
}
|
|
1054
|
+
return counts;
|
|
1055
|
+
}
|
|
911
1056
|
}
|
|
912
1057
|
//# sourceMappingURL=ImportCoordinator.js.map
|
|
@@ -205,6 +205,9 @@ export class SmartExcelImporter {
|
|
|
205
205
|
evidence: `Extracted from: "${definition.substring(0, 100)}..."`
|
|
206
206
|
});
|
|
207
207
|
}
|
|
208
|
+
// ============================================
|
|
209
|
+
// v4.9.0: Enhanced column-based relationship detection
|
|
210
|
+
// ============================================
|
|
208
211
|
// Parse explicit "Related Terms" column
|
|
209
212
|
if (relatedTerms) {
|
|
210
213
|
const terms = relatedTerms.split(/[,;]/).map(t => t.trim()).filter(Boolean);
|
|
@@ -223,6 +226,53 @@ export class SmartExcelImporter {
|
|
|
223
226
|
}
|
|
224
227
|
}
|
|
225
228
|
}
|
|
229
|
+
// v4.9.0: Check for additional relationship-indicating columns
|
|
230
|
+
// Expanded patterns for various relationship types
|
|
231
|
+
const relationshipColumnPatterns = [
|
|
232
|
+
{ pattern: /^(location|home|lives in|resides|dwelling|place)$/i, defaultType: VerbType.LocatedAt },
|
|
233
|
+
{ pattern: /^(owner|owned by|belongs to|possessed by|wielder)$/i, defaultType: VerbType.PartOf },
|
|
234
|
+
{ pattern: /^(created by|made by|invented by|authored by|creator|author)$/i, defaultType: VerbType.CreatedBy },
|
|
235
|
+
{ pattern: /^(uses|utilizes|requires|needs|employs|tool|weapon|item)$/i, defaultType: VerbType.Uses },
|
|
236
|
+
{ pattern: /^(member of|part of|within|inside|group|organization)$/i, defaultType: VerbType.PartOf },
|
|
237
|
+
{ pattern: /^(knows|friend|associate|colleague|ally|companion)$/i, defaultType: VerbType.FriendOf },
|
|
238
|
+
{ pattern: /^(connection|link|reference|see also|related to)$/i, defaultType: VerbType.RelatedTo }
|
|
239
|
+
];
|
|
240
|
+
// Check all columns in the row
|
|
241
|
+
for (const [columnName, columnValue] of Object.entries(row)) {
|
|
242
|
+
// Skip standard columns
|
|
243
|
+
if (!columnValue || columnName === columns.term || columnName === columns.definition || columnName === columns.type) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
// Find matching relationship pattern
|
|
247
|
+
const matchedPattern = relationshipColumnPatterns.find(rcp => rcp.pattern.test(columnName));
|
|
248
|
+
if (matchedPattern && typeof columnValue === 'string') {
|
|
249
|
+
// Parse comma/semicolon-separated values
|
|
250
|
+
const references = columnValue.split(/[,;]+/).map(s => s.trim()).filter(Boolean);
|
|
251
|
+
for (const ref of references) {
|
|
252
|
+
if (ref.toLowerCase() !== term.toLowerCase()) {
|
|
253
|
+
// Use SmartRelationshipExtractor for better type inference, fallback to pattern default
|
|
254
|
+
let verbType;
|
|
255
|
+
try {
|
|
256
|
+
verbType = await this.inferRelationship(term, ref, `${term}'s ${columnName}: ${ref}. ${definition}`, mainEntityType);
|
|
257
|
+
// If inference returns generic type, use column pattern hint
|
|
258
|
+
if (verbType === VerbType.RelatedTo) {
|
|
259
|
+
verbType = matchedPattern.defaultType;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
verbType = matchedPattern.defaultType;
|
|
264
|
+
}
|
|
265
|
+
relationships.push({
|
|
266
|
+
from: entityId,
|
|
267
|
+
to: ref,
|
|
268
|
+
type: verbType,
|
|
269
|
+
confidence: 0.9, // High confidence for explicit columns
|
|
270
|
+
evidence: `Column "${columnName}": ${ref}`
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
226
276
|
}
|
|
227
277
|
return {
|
|
228
278
|
term,
|
|
@@ -616,7 +616,10 @@ export class VirtualFileSystem {
|
|
|
616
616
|
from: parentId,
|
|
617
617
|
to: entity,
|
|
618
618
|
type: VerbType.Contains,
|
|
619
|
-
metadata: {
|
|
619
|
+
metadata: {
|
|
620
|
+
isVFS: true, // v4.5.1: Mark as VFS relationship
|
|
621
|
+
relationshipType: 'vfs' // v4.9.0: Standardized relationship type metadata
|
|
622
|
+
}
|
|
620
623
|
});
|
|
621
624
|
}
|
|
622
625
|
// Update path resolver cache
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soulcraft/brainy",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.9.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",
|