@soulcraft/brainy 2.0.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/augmentations/AugmentationMetadataContract.d.ts +94 -0
- package/dist/augmentations/AugmentationMetadataContract.js +306 -0
- package/dist/augmentations/apiServerAugmentation.d.ts +1 -0
- package/dist/augmentations/apiServerAugmentation.js +1 -0
- package/dist/augmentations/batchProcessingAugmentation.d.ts +1 -0
- package/dist/augmentations/batchProcessingAugmentation.js +1 -0
- package/dist/augmentations/brainyAugmentation.d.ts +16 -0
- package/dist/augmentations/cacheAugmentation.d.ts +1 -0
- package/dist/augmentations/cacheAugmentation.js +1 -0
- package/dist/augmentations/conduitAugmentations.d.ts +1 -0
- package/dist/augmentations/conduitAugmentations.js +1 -0
- package/dist/augmentations/connectionPoolAugmentation.d.ts +1 -0
- package/dist/augmentations/connectionPoolAugmentation.js +1 -0
- package/dist/augmentations/entityRegistryAugmentation.d.ts +2 -0
- package/dist/augmentations/entityRegistryAugmentation.js +2 -0
- package/dist/augmentations/indexAugmentation.d.ts +1 -0
- package/dist/augmentations/indexAugmentation.js +1 -0
- package/dist/augmentations/intelligentVerbScoringAugmentation.d.ts +4 -0
- package/dist/augmentations/intelligentVerbScoringAugmentation.js +4 -0
- package/dist/augmentations/metadataEnforcer.d.ts +20 -0
- package/dist/augmentations/metadataEnforcer.js +171 -0
- package/dist/augmentations/metricsAugmentation.d.ts +2 -7
- package/dist/augmentations/metricsAugmentation.js +1 -0
- package/dist/augmentations/monitoringAugmentation.d.ts +1 -0
- package/dist/augmentations/monitoringAugmentation.js +1 -0
- package/dist/augmentations/neuralImport.d.ts +16 -3
- package/dist/augmentations/neuralImport.js +199 -55
- package/dist/augmentations/requestDeduplicatorAugmentation.d.ts +1 -0
- package/dist/augmentations/requestDeduplicatorAugmentation.js +1 -0
- package/dist/augmentations/serverSearchAugmentations.d.ts +2 -0
- package/dist/augmentations/serverSearchAugmentations.js +2 -0
- package/dist/augmentations/storageAugmentation.d.ts +1 -0
- package/dist/augmentations/storageAugmentation.js +1 -0
- package/dist/augmentations/synapseAugmentation.d.ts +4 -0
- package/dist/augmentations/synapseAugmentation.js +4 -0
- package/dist/augmentations/typeMatching/intelligentTypeMatcher.d.ts +83 -0
- package/dist/augmentations/typeMatching/intelligentTypeMatcher.js +425 -0
- package/dist/augmentations/walAugmentation.d.ts +1 -0
- package/dist/augmentations/walAugmentation.js +1 -0
- package/dist/brainyData.d.ts +32 -5
- package/dist/brainyData.js +263 -111
- package/dist/importManager.d.ts +78 -0
- package/dist/importManager.js +258 -0
- package/dist/neural/embeddedPatterns.d.ts +1 -1
- package/dist/neural/embeddedPatterns.js +1 -1
- package/dist/triple/TripleIntelligence.d.ts +4 -0
- package/dist/triple/TripleIntelligence.js +39 -9
- package/dist/utils/deletedItemsIndex.d.ts +59 -0
- package/dist/utils/deletedItemsIndex.js +98 -0
- package/dist/utils/ensureDeleted.d.ts +38 -0
- package/dist/utils/ensureDeleted.js +79 -0
- package/dist/utils/metadataFilter.js +5 -0
- package/dist/utils/metadataIndex.d.ts +4 -0
- package/dist/utils/metadataIndex.js +45 -0
- package/dist/utils/metadataNamespace.d.ts +113 -0
- package/dist/utils/metadataNamespace.js +162 -0
- package/dist/utils/periodicCleanup.d.ts +87 -0
- package/dist/utils/periodicCleanup.js +219 -0
- package/package.json +13 -5
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime enforcement of metadata contracts
|
|
3
|
+
* Ensures augmentations only access declared fields
|
|
4
|
+
*/
|
|
5
|
+
export class MetadataEnforcer {
|
|
6
|
+
/**
|
|
7
|
+
* Enforce metadata access based on augmentation contract
|
|
8
|
+
* Returns a wrapped metadata object that enforces the contract
|
|
9
|
+
*/
|
|
10
|
+
static enforce(augmentation, metadata, operation = 'write') {
|
|
11
|
+
// Handle simple contracts
|
|
12
|
+
if (augmentation.metadata === 'none') {
|
|
13
|
+
// No access at all
|
|
14
|
+
if (operation === 'read')
|
|
15
|
+
return null;
|
|
16
|
+
throw new Error(`Augmentation '${augmentation.name}' has metadata='none' - cannot access metadata`);
|
|
17
|
+
}
|
|
18
|
+
if (augmentation.metadata === 'readonly') {
|
|
19
|
+
if (operation === 'read') {
|
|
20
|
+
// Return frozen deep clone for read-only access
|
|
21
|
+
return deepFreeze(deepClone(metadata));
|
|
22
|
+
}
|
|
23
|
+
throw new Error(`Augmentation '${augmentation.name}' has metadata='readonly' - cannot write`);
|
|
24
|
+
}
|
|
25
|
+
// Handle specific field access
|
|
26
|
+
const access = augmentation.metadata;
|
|
27
|
+
if (operation === 'read') {
|
|
28
|
+
// For reads, filter to allowed fields
|
|
29
|
+
if (access.reads === '*') {
|
|
30
|
+
return deepClone(metadata); // Can read everything
|
|
31
|
+
}
|
|
32
|
+
if (!access.reads) {
|
|
33
|
+
return {}; // No read access
|
|
34
|
+
}
|
|
35
|
+
// Filter to specific fields
|
|
36
|
+
const filtered = {};
|
|
37
|
+
for (const field of access.reads) {
|
|
38
|
+
if (field.includes('.')) {
|
|
39
|
+
// Handle nested fields like '_brainy.deleted'
|
|
40
|
+
const parts = field.split('.');
|
|
41
|
+
let source = metadata;
|
|
42
|
+
let target = filtered;
|
|
43
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
44
|
+
const part = parts[i];
|
|
45
|
+
if (!source[part])
|
|
46
|
+
break;
|
|
47
|
+
if (!target[part])
|
|
48
|
+
target[part] = {};
|
|
49
|
+
source = source[part];
|
|
50
|
+
target = target[part];
|
|
51
|
+
}
|
|
52
|
+
const lastPart = parts[parts.length - 1];
|
|
53
|
+
if (source && lastPart in source) {
|
|
54
|
+
target[lastPart] = source[lastPart];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Simple field
|
|
59
|
+
if (field in metadata) {
|
|
60
|
+
filtered[field] = metadata[field];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return filtered;
|
|
65
|
+
}
|
|
66
|
+
// For writes, create a proxy that validates
|
|
67
|
+
return new Proxy(metadata, {
|
|
68
|
+
set(target, prop, value) {
|
|
69
|
+
const field = String(prop);
|
|
70
|
+
// Check if write is allowed
|
|
71
|
+
if (access.writes === '*') {
|
|
72
|
+
// Can write anything
|
|
73
|
+
target[prop] = value;
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (!access.writes || !access.writes.includes(field)) {
|
|
77
|
+
throw new Error(`Augmentation '${augmentation.name}' cannot write to field '${field}'. ` +
|
|
78
|
+
`Allowed writes: ${access.writes?.join(', ') || 'none'}`);
|
|
79
|
+
}
|
|
80
|
+
// Check namespace if specified
|
|
81
|
+
if (access.namespace && !field.startsWith(access.namespace)) {
|
|
82
|
+
console.warn(`Augmentation '${augmentation.name}' writing outside its namespace. ` +
|
|
83
|
+
`Expected: ${access.namespace}.*, got: ${field}`);
|
|
84
|
+
}
|
|
85
|
+
target[prop] = value;
|
|
86
|
+
return true;
|
|
87
|
+
},
|
|
88
|
+
deleteProperty(target, prop) {
|
|
89
|
+
const field = String(prop);
|
|
90
|
+
// Deletion counts as a write
|
|
91
|
+
if (access.writes === '*' || access.writes?.includes(field)) {
|
|
92
|
+
delete target[prop];
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
throw new Error(`Augmentation '${augmentation.name}' cannot delete field '${field}'`);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Validate that an augmentation's actual behavior matches its contract
|
|
101
|
+
* Used in testing to verify contracts are accurate
|
|
102
|
+
*/
|
|
103
|
+
static async validateContract(augmentation, testMetadata = { test: 'data', _brainy: { deleted: false } }) {
|
|
104
|
+
const violations = [];
|
|
105
|
+
// Test read access
|
|
106
|
+
try {
|
|
107
|
+
const readable = this.enforce(augmentation, testMetadata, 'read');
|
|
108
|
+
if (augmentation.metadata === 'none' && readable !== null) {
|
|
109
|
+
violations.push(`Contract says 'none' but got readable metadata`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
violations.push(`Read enforcement error: ${error}`);
|
|
114
|
+
}
|
|
115
|
+
// Test write access
|
|
116
|
+
try {
|
|
117
|
+
const writable = this.enforce(augmentation, testMetadata, 'write');
|
|
118
|
+
if (augmentation.metadata === 'none') {
|
|
119
|
+
violations.push(`Contract says 'none' but got writable metadata`);
|
|
120
|
+
}
|
|
121
|
+
if (augmentation.metadata === 'readonly') {
|
|
122
|
+
// Try to write - should fail
|
|
123
|
+
try {
|
|
124
|
+
writable.testWrite = 'value';
|
|
125
|
+
violations.push(`Contract says 'readonly' but write succeeded`);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Expected to fail
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
// Expected for 'none' and 'readonly' on write
|
|
134
|
+
if (augmentation.metadata !== 'none' && augmentation.metadata !== 'readonly') {
|
|
135
|
+
violations.push(`Write enforcement error: ${error}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
valid: violations.length === 0,
|
|
140
|
+
violations
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Helper functions
|
|
145
|
+
function deepClone(obj) {
|
|
146
|
+
if (obj === null || typeof obj !== 'object')
|
|
147
|
+
return obj;
|
|
148
|
+
if (obj instanceof Date)
|
|
149
|
+
return new Date(obj);
|
|
150
|
+
if (obj instanceof Array)
|
|
151
|
+
return obj.map(item => deepClone(item));
|
|
152
|
+
const cloned = {};
|
|
153
|
+
for (const key in obj) {
|
|
154
|
+
if (obj.hasOwnProperty(key)) {
|
|
155
|
+
cloned[key] = deepClone(obj[key]);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return cloned;
|
|
159
|
+
}
|
|
160
|
+
function deepFreeze(obj) {
|
|
161
|
+
Object.freeze(obj);
|
|
162
|
+
Object.getOwnPropertyNames(obj).forEach(prop => {
|
|
163
|
+
if (obj[prop] !== null &&
|
|
164
|
+
(typeof obj[prop] === 'object' || typeof obj[prop] === 'function') &&
|
|
165
|
+
!Object.isFrozen(obj[prop])) {
|
|
166
|
+
deepFreeze(obj[prop]);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
return obj;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=metadataEnforcer.js.map
|
|
@@ -27,6 +27,7 @@ export interface MetricsConfig {
|
|
|
27
27
|
* - Zero-config with smart defaults
|
|
28
28
|
*/
|
|
29
29
|
export declare class MetricsAugmentation extends BaseAugmentation {
|
|
30
|
+
readonly metadata: "readonly";
|
|
30
31
|
readonly name = "metrics";
|
|
31
32
|
readonly timing: "after";
|
|
32
33
|
operations: ("add" | "search" | "delete" | "clear" | "all")[];
|
|
@@ -126,13 +127,7 @@ export declare class MetricsAugmentation extends BaseAugmentation {
|
|
|
126
127
|
averageSearchTimeMs: number;
|
|
127
128
|
searchesLastHour: number;
|
|
128
129
|
searchesLastDay: number;
|
|
129
|
-
topSearchTerms
|
|
130
|
-
/**
|
|
131
|
-
* Update storage size metrics
|
|
132
|
-
*/
|
|
133
|
-
? /**
|
|
134
|
-
* Update storage size metrics
|
|
135
|
-
*/: string[];
|
|
130
|
+
topSearchTerms?: string[];
|
|
136
131
|
} | undefined;
|
|
137
132
|
verbStatistics?: {
|
|
138
133
|
totalVerbs: number;
|
|
@@ -21,6 +21,7 @@ import { StatisticsCollector } from '../utils/statisticsCollector.js';
|
|
|
21
21
|
export class MetricsAugmentation extends BaseAugmentation {
|
|
22
22
|
constructor(config = {}) {
|
|
23
23
|
super();
|
|
24
|
+
this.metadata = 'readonly'; // Reads metadata for metrics
|
|
24
25
|
this.name = 'metrics';
|
|
25
26
|
this.timing = 'after';
|
|
26
27
|
this.operations = ['add', 'search', 'delete', 'clear', 'all'];
|
|
@@ -28,6 +28,7 @@ export interface MonitoringConfig {
|
|
|
28
28
|
* - Zero-config with smart defaults
|
|
29
29
|
*/
|
|
30
30
|
export declare class MonitoringAugmentation extends BaseAugmentation {
|
|
31
|
+
readonly metadata: "readonly";
|
|
31
32
|
readonly name = "monitoring";
|
|
32
33
|
readonly timing: "after";
|
|
33
34
|
operations: ("search" | "add" | "delete" | "all")[];
|
|
@@ -23,6 +23,7 @@ import { DistributedConfigManager as ConfigManager } from '../distributed/config
|
|
|
23
23
|
export class MonitoringAugmentation extends BaseAugmentation {
|
|
24
24
|
constructor(config = {}) {
|
|
25
25
|
super();
|
|
26
|
+
this.metadata = 'readonly'; // Reads metadata for monitoring
|
|
26
27
|
this.name = 'monitoring';
|
|
27
28
|
this.timing = 'after';
|
|
28
29
|
this.operations = ['search', 'add', 'delete', 'all'];
|
|
@@ -55,10 +55,15 @@ export interface NeuralImportConfig {
|
|
|
55
55
|
export declare class NeuralImportAugmentation extends BaseAugmentation {
|
|
56
56
|
readonly name = "neural-import";
|
|
57
57
|
readonly timing: "before";
|
|
58
|
+
readonly metadata: {
|
|
59
|
+
reads: "*";
|
|
60
|
+
writes: string[];
|
|
61
|
+
};
|
|
58
62
|
operations: ("add" | "addNoun" | "addVerb" | "all")[];
|
|
59
63
|
readonly priority = 80;
|
|
60
64
|
private config;
|
|
61
65
|
private analysisCache;
|
|
66
|
+
private typeMatcher;
|
|
62
67
|
constructor(config?: Partial<NeuralImportConfig>);
|
|
63
68
|
protected onInitialize(): Promise<void>;
|
|
64
69
|
protected onShutdown(): Promise<void>;
|
|
@@ -79,15 +84,23 @@ export declare class NeuralImportAugmentation extends BaseAugmentation {
|
|
|
79
84
|
*/
|
|
80
85
|
private parseRawData;
|
|
81
86
|
/**
|
|
82
|
-
* Parse CSV data
|
|
87
|
+
* Parse CSV data - handles quoted values, escaped quotes, and edge cases
|
|
83
88
|
*/
|
|
84
89
|
private parseCSV;
|
|
90
|
+
/**
|
|
91
|
+
* Parse YAML data
|
|
92
|
+
*/
|
|
93
|
+
private parseYAML;
|
|
94
|
+
/**
|
|
95
|
+
* Parse a YAML value (handle strings, numbers, booleans, null)
|
|
96
|
+
*/
|
|
97
|
+
private parseYAMLValue;
|
|
85
98
|
/**
|
|
86
99
|
* Perform neural analysis on parsed data
|
|
87
100
|
*/
|
|
88
101
|
private performNeuralAnalysis;
|
|
89
102
|
/**
|
|
90
|
-
* Infer noun type from object structure
|
|
103
|
+
* Infer noun type from object structure using intelligent type matching
|
|
91
104
|
*/
|
|
92
105
|
private inferNounType;
|
|
93
106
|
/**
|
|
@@ -95,7 +108,7 @@ export declare class NeuralImportAugmentation extends BaseAugmentation {
|
|
|
95
108
|
*/
|
|
96
109
|
private detectRelationships;
|
|
97
110
|
/**
|
|
98
|
-
* Infer verb type from field name
|
|
111
|
+
* Infer verb type from field name using intelligent type matching
|
|
99
112
|
*/
|
|
100
113
|
private inferVerbType;
|
|
101
114
|
/**
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { BaseAugmentation } from './brainyAugmentation.js';
|
|
10
10
|
import * as path from '../universal/path.js';
|
|
11
|
+
import { getTypeMatcher } from './typeMatching/intelligentTypeMatcher.js';
|
|
12
|
+
import { prodLog } from '../utils/logger.js';
|
|
11
13
|
/**
|
|
12
14
|
* Neural Import Augmentation - Unified Implementation
|
|
13
15
|
* Processes data with AI before storage operations
|
|
@@ -17,9 +19,14 @@ export class NeuralImportAugmentation extends BaseAugmentation {
|
|
|
17
19
|
super();
|
|
18
20
|
this.name = 'neural-import';
|
|
19
21
|
this.timing = 'before'; // Process data before storage
|
|
22
|
+
this.metadata = {
|
|
23
|
+
reads: '*', // Needs to read data for analysis
|
|
24
|
+
writes: ['_neuralProcessed', '_neuralConfidence', '_detectedEntities', '_detectedRelationships', '_neuralInsights', 'nounType', 'verbType']
|
|
25
|
+
}; // Enriches metadata with neural analysis
|
|
20
26
|
this.operations = ['add', 'addNoun', 'addVerb', 'all']; // Use 'all' to catch batch operations
|
|
21
27
|
this.priority = 80; // High priority for data processing
|
|
22
28
|
this.analysisCache = new Map();
|
|
29
|
+
this.typeMatcher = null;
|
|
23
30
|
this.config = {
|
|
24
31
|
confidenceThreshold: 0.7,
|
|
25
32
|
enableWeights: true,
|
|
@@ -29,7 +36,13 @@ export class NeuralImportAugmentation extends BaseAugmentation {
|
|
|
29
36
|
};
|
|
30
37
|
}
|
|
31
38
|
async onInitialize() {
|
|
32
|
-
|
|
39
|
+
try {
|
|
40
|
+
this.typeMatcher = await getTypeMatcher();
|
|
41
|
+
this.log('🧠 Neural Import augmentation initialized with intelligent type matching');
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
this.log('⚠️ Failed to initialize type matcher, falling back to heuristics', 'warn');
|
|
45
|
+
}
|
|
33
46
|
}
|
|
34
47
|
async onShutdown() {
|
|
35
48
|
this.analysisCache.clear();
|
|
@@ -128,13 +141,7 @@ export class NeuralImportAugmentation extends BaseAugmentation {
|
|
|
128
141
|
return this.parseCSV(content);
|
|
129
142
|
case 'yaml':
|
|
130
143
|
case 'yml':
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
return JSON.parse(content); // Placeholder
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
return [{ text: content }];
|
|
137
|
-
}
|
|
144
|
+
return this.parseYAML(content);
|
|
138
145
|
case 'txt':
|
|
139
146
|
case 'text':
|
|
140
147
|
// Split text into sentences/paragraphs for analysis
|
|
@@ -145,24 +152,174 @@ export class NeuralImportAugmentation extends BaseAugmentation {
|
|
|
145
152
|
}
|
|
146
153
|
}
|
|
147
154
|
/**
|
|
148
|
-
* Parse CSV data
|
|
155
|
+
* Parse CSV data - handles quoted values, escaped quotes, and edge cases
|
|
149
156
|
*/
|
|
150
157
|
parseCSV(content) {
|
|
151
|
-
const lines = content.split('\n')
|
|
158
|
+
const lines = content.split('\n');
|
|
152
159
|
if (lines.length === 0)
|
|
153
160
|
return [];
|
|
154
|
-
|
|
161
|
+
// Parse a CSV line handling quotes
|
|
162
|
+
const parseLine = (line) => {
|
|
163
|
+
const result = [];
|
|
164
|
+
let current = '';
|
|
165
|
+
let inQuotes = false;
|
|
166
|
+
let i = 0;
|
|
167
|
+
while (i < line.length) {
|
|
168
|
+
const char = line[i];
|
|
169
|
+
const nextChar = line[i + 1];
|
|
170
|
+
if (char === '"') {
|
|
171
|
+
if (inQuotes && nextChar === '"') {
|
|
172
|
+
// Escaped quote
|
|
173
|
+
current += '"';
|
|
174
|
+
i += 2;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
// Toggle quote mode
|
|
178
|
+
inQuotes = !inQuotes;
|
|
179
|
+
i++;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else if (char === ',' && !inQuotes) {
|
|
183
|
+
// Field separator
|
|
184
|
+
result.push(current.trim());
|
|
185
|
+
current = '';
|
|
186
|
+
i++;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
current += char;
|
|
190
|
+
i++;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Add last field
|
|
194
|
+
result.push(current.trim());
|
|
195
|
+
return result;
|
|
196
|
+
};
|
|
197
|
+
// Parse headers
|
|
198
|
+
const headers = parseLine(lines[0]);
|
|
155
199
|
const data = [];
|
|
200
|
+
// Parse data rows
|
|
156
201
|
for (let i = 1; i < lines.length; i++) {
|
|
157
|
-
const
|
|
202
|
+
const line = lines[i].trim();
|
|
203
|
+
if (!line)
|
|
204
|
+
continue; // Skip empty lines
|
|
205
|
+
const values = parseLine(line);
|
|
158
206
|
const row = {};
|
|
159
207
|
headers.forEach((header, index) => {
|
|
160
|
-
|
|
208
|
+
const value = values[index] || '';
|
|
209
|
+
// Try to parse numbers
|
|
210
|
+
const num = Number(value);
|
|
211
|
+
row[header] = !isNaN(num) && value !== '' ? num : value;
|
|
161
212
|
});
|
|
162
213
|
data.push(row);
|
|
163
214
|
}
|
|
164
215
|
return data;
|
|
165
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Parse YAML data
|
|
219
|
+
*/
|
|
220
|
+
parseYAML(content) {
|
|
221
|
+
try {
|
|
222
|
+
// Simple YAML parser for basic structures
|
|
223
|
+
// For full YAML support, we'd use js-yaml library
|
|
224
|
+
const lines = content.split('\n');
|
|
225
|
+
const result = [];
|
|
226
|
+
let currentObject = null;
|
|
227
|
+
let currentIndent = 0;
|
|
228
|
+
for (const line of lines) {
|
|
229
|
+
const trimmed = line.trim();
|
|
230
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
231
|
+
continue; // Skip empty lines and comments
|
|
232
|
+
// Calculate indentation
|
|
233
|
+
const indent = line.length - line.trimStart().length;
|
|
234
|
+
// Check for array item
|
|
235
|
+
if (trimmed.startsWith('- ')) {
|
|
236
|
+
const value = trimmed.substring(2).trim();
|
|
237
|
+
if (indent === 0) {
|
|
238
|
+
// Top-level array item
|
|
239
|
+
if (value.includes(':')) {
|
|
240
|
+
// Object in array
|
|
241
|
+
currentObject = {};
|
|
242
|
+
result.push(currentObject);
|
|
243
|
+
const [key, val] = value.split(':').map(s => s.trim());
|
|
244
|
+
currentObject[key] = this.parseYAMLValue(val);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
result.push(this.parseYAMLValue(value));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else if (currentObject) {
|
|
251
|
+
// Nested array
|
|
252
|
+
const lastKey = Object.keys(currentObject).pop();
|
|
253
|
+
if (lastKey) {
|
|
254
|
+
if (!Array.isArray(currentObject[lastKey])) {
|
|
255
|
+
currentObject[lastKey] = [];
|
|
256
|
+
}
|
|
257
|
+
currentObject[lastKey].push(this.parseYAMLValue(value));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
else if (trimmed.includes(':')) {
|
|
262
|
+
// Key-value pair
|
|
263
|
+
const colonIndex = trimmed.indexOf(':');
|
|
264
|
+
const key = trimmed.substring(0, colonIndex).trim();
|
|
265
|
+
const value = trimmed.substring(colonIndex + 1).trim();
|
|
266
|
+
if (indent === 0) {
|
|
267
|
+
// Top-level object
|
|
268
|
+
if (!currentObject) {
|
|
269
|
+
currentObject = {};
|
|
270
|
+
result.push(currentObject);
|
|
271
|
+
}
|
|
272
|
+
currentObject[key] = this.parseYAMLValue(value);
|
|
273
|
+
currentIndent = 0;
|
|
274
|
+
}
|
|
275
|
+
else if (currentObject) {
|
|
276
|
+
// Nested object
|
|
277
|
+
if (indent > currentIndent && !value) {
|
|
278
|
+
// Start of nested object
|
|
279
|
+
const lastKey = Object.keys(currentObject).pop();
|
|
280
|
+
if (lastKey) {
|
|
281
|
+
currentObject[lastKey] = { [key]: '' };
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
currentObject[key] = this.parseYAMLValue(value);
|
|
286
|
+
}
|
|
287
|
+
currentIndent = indent;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// If we built a single object and not an array, wrap it
|
|
292
|
+
if (result.length === 0 && currentObject) {
|
|
293
|
+
result.push(currentObject);
|
|
294
|
+
}
|
|
295
|
+
return result.length > 0 ? result : [{ text: content }];
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
prodLog.warn('YAML parsing failed, treating as text:', error);
|
|
299
|
+
return [{ text: content }];
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Parse a YAML value (handle strings, numbers, booleans, null)
|
|
304
|
+
*/
|
|
305
|
+
parseYAMLValue(value) {
|
|
306
|
+
if (!value || value === '~' || value === 'null')
|
|
307
|
+
return null;
|
|
308
|
+
if (value === 'true')
|
|
309
|
+
return true;
|
|
310
|
+
if (value === 'false')
|
|
311
|
+
return false;
|
|
312
|
+
// Remove quotes if present
|
|
313
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
314
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
315
|
+
return value.slice(1, -1);
|
|
316
|
+
}
|
|
317
|
+
// Try to parse as number
|
|
318
|
+
const num = Number(value);
|
|
319
|
+
if (!isNaN(num) && value !== '')
|
|
320
|
+
return num;
|
|
321
|
+
return value;
|
|
322
|
+
}
|
|
166
323
|
/**
|
|
167
324
|
* Perform neural analysis on parsed data
|
|
168
325
|
*/
|
|
@@ -177,14 +334,14 @@ export class NeuralImportAugmentation extends BaseAugmentation {
|
|
|
177
334
|
const entityId = item.id || item.name || item.title || `entity_${Date.now()}_${Math.random()}`;
|
|
178
335
|
detectedEntities.push({
|
|
179
336
|
originalData: item,
|
|
180
|
-
nounType: this.inferNounType(item),
|
|
337
|
+
nounType: await this.inferNounType(item),
|
|
181
338
|
confidence: 0.85,
|
|
182
339
|
suggestedId: String(entityId),
|
|
183
340
|
reasoning: 'Detected from structured data',
|
|
184
341
|
alternativeTypes: []
|
|
185
342
|
});
|
|
186
343
|
// Detect relationships from references
|
|
187
|
-
this.detectRelationships(item, entityId, detectedRelationships);
|
|
344
|
+
await this.detectRelationships(item, entityId, detectedRelationships);
|
|
188
345
|
}
|
|
189
346
|
}
|
|
190
347
|
// Generate insights
|
|
@@ -216,36 +373,31 @@ export class NeuralImportAugmentation extends BaseAugmentation {
|
|
|
216
373
|
};
|
|
217
374
|
}
|
|
218
375
|
/**
|
|
219
|
-
* Infer noun type from object structure
|
|
376
|
+
* Infer noun type from object structure using intelligent type matching
|
|
220
377
|
*/
|
|
221
|
-
inferNounType(obj) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
return 'Resource';
|
|
233
|
-
if (obj.lat || obj.longitude)
|
|
234
|
-
return 'Location';
|
|
235
|
-
// Default fallback
|
|
236
|
-
return 'Entity';
|
|
378
|
+
async inferNounType(obj) {
|
|
379
|
+
if (!this.typeMatcher) {
|
|
380
|
+
// Initialize type matcher if not available
|
|
381
|
+
this.typeMatcher = await getTypeMatcher();
|
|
382
|
+
}
|
|
383
|
+
const result = await this.typeMatcher.matchNounType(obj);
|
|
384
|
+
// Log if confidence is low for debugging
|
|
385
|
+
if (result.confidence < 0.5) {
|
|
386
|
+
this.log(`Low confidence (${result.confidence.toFixed(2)}) for noun type: ${result.type}`, 'warn');
|
|
387
|
+
}
|
|
388
|
+
return result.type;
|
|
237
389
|
}
|
|
238
390
|
/**
|
|
239
391
|
* Detect relationships from object references
|
|
240
392
|
*/
|
|
241
|
-
detectRelationships(obj, sourceId, relationships) {
|
|
393
|
+
async detectRelationships(obj, sourceId, relationships) {
|
|
242
394
|
// Look for reference patterns
|
|
243
395
|
for (const [key, value] of Object.entries(obj)) {
|
|
244
396
|
if (key.endsWith('Id') || key.endsWith('_id') || key === 'parentId' || key === 'userId') {
|
|
245
397
|
relationships.push({
|
|
246
398
|
sourceId,
|
|
247
399
|
targetId: String(value),
|
|
248
|
-
verbType: this.inferVerbType(key),
|
|
400
|
+
verbType: await this.inferVerbType(key, obj, { id: value }),
|
|
249
401
|
confidence: 0.75,
|
|
250
402
|
weight: 1,
|
|
251
403
|
reasoning: `Reference detected in field: ${key}`,
|
|
@@ -259,7 +411,7 @@ export class NeuralImportAugmentation extends BaseAugmentation {
|
|
|
259
411
|
relationships.push({
|
|
260
412
|
sourceId,
|
|
261
413
|
targetId: String(targetId),
|
|
262
|
-
verbType: this.inferVerbType(key),
|
|
414
|
+
verbType: await this.inferVerbType(key, obj, { id: targetId }),
|
|
263
415
|
confidence: 0.7,
|
|
264
416
|
weight: 1,
|
|
265
417
|
reasoning: `Array reference in field: ${key}`,
|
|
@@ -271,27 +423,19 @@ export class NeuralImportAugmentation extends BaseAugmentation {
|
|
|
271
423
|
}
|
|
272
424
|
}
|
|
273
425
|
/**
|
|
274
|
-
* Infer verb type from field name
|
|
426
|
+
* Infer verb type from field name using intelligent type matching
|
|
275
427
|
*/
|
|
276
|
-
inferVerbType(fieldName) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
return 'createdBy';
|
|
288
|
-
if (normalized.includes('member'))
|
|
289
|
-
return 'memberOf';
|
|
290
|
-
if (normalized.includes('tag'))
|
|
291
|
-
return 'taggedWith';
|
|
292
|
-
if (normalized.includes('category'))
|
|
293
|
-
return 'categorizedAs';
|
|
294
|
-
return 'relatedTo';
|
|
428
|
+
async inferVerbType(fieldName, sourceObj, targetObj) {
|
|
429
|
+
if (!this.typeMatcher) {
|
|
430
|
+
// Initialize type matcher if not available
|
|
431
|
+
this.typeMatcher = await getTypeMatcher();
|
|
432
|
+
}
|
|
433
|
+
const result = await this.typeMatcher.matchVerbType(sourceObj, targetObj, fieldName);
|
|
434
|
+
// Log if confidence is low for debugging
|
|
435
|
+
if (result.confidence < 0.5) {
|
|
436
|
+
this.log(`Low confidence (${result.confidence.toFixed(2)}) for verb type: ${result.type}`, 'warn');
|
|
437
|
+
}
|
|
438
|
+
return result.type;
|
|
295
439
|
}
|
|
296
440
|
/**
|
|
297
441
|
* Group entities by type
|
|
@@ -13,6 +13,7 @@ interface DeduplicatorConfig {
|
|
|
13
13
|
export declare class RequestDeduplicatorAugmentation extends BaseAugmentation {
|
|
14
14
|
name: string;
|
|
15
15
|
timing: "around";
|
|
16
|
+
metadata: "none";
|
|
16
17
|
operations: ("search" | "searchText" | "searchByNounTypes" | "findSimilar" | "get")[];
|
|
17
18
|
priority: number;
|
|
18
19
|
private pendingRequests;
|
|
@@ -10,6 +10,7 @@ export class RequestDeduplicatorAugmentation extends BaseAugmentation {
|
|
|
10
10
|
super();
|
|
11
11
|
this.name = 'RequestDeduplicator';
|
|
12
12
|
this.timing = 'around';
|
|
13
|
+
this.metadata = 'none'; // Doesn't access metadata
|
|
13
14
|
this.operations = ['search', 'searchText', 'searchByNounTypes', 'findSimilar', 'get'];
|
|
14
15
|
this.priority = 50; // Performance optimization
|
|
15
16
|
this.pendingRequests = new Map();
|
|
@@ -16,6 +16,7 @@ import { BrainyDataInterface } from '../types/brainyDataInterface.js';
|
|
|
16
16
|
export declare class ServerSearchConduitAugmentation extends BaseAugmentation {
|
|
17
17
|
readonly name = "server-search-conduit";
|
|
18
18
|
readonly timing: "after";
|
|
19
|
+
readonly metadata: "readonly";
|
|
19
20
|
operations: ("addNoun" | "delete" | "addVerb")[];
|
|
20
21
|
readonly priority = 20;
|
|
21
22
|
private localDb;
|
|
@@ -101,6 +102,7 @@ export declare class ServerSearchConduitAugmentation extends BaseAugmentation {
|
|
|
101
102
|
export declare class ServerSearchActivationAugmentation extends BaseAugmentation {
|
|
102
103
|
readonly name = "server-search-activation";
|
|
103
104
|
readonly timing: "after";
|
|
105
|
+
readonly metadata: "readonly";
|
|
104
106
|
operations: ("search" | "addNoun")[];
|
|
105
107
|
readonly priority = 20;
|
|
106
108
|
private conduitAugmentation;
|
|
@@ -16,6 +16,7 @@ export class ServerSearchConduitAugmentation extends BaseAugmentation {
|
|
|
16
16
|
super();
|
|
17
17
|
this.name = 'server-search-conduit';
|
|
18
18
|
this.timing = 'after';
|
|
19
|
+
this.metadata = 'readonly'; // Reads metadata to sync with server
|
|
19
20
|
this.operations = ['addNoun', 'delete', 'addVerb'];
|
|
20
21
|
this.priority = 20;
|
|
21
22
|
this.localDb = null;
|
|
@@ -310,6 +311,7 @@ export class ServerSearchActivationAugmentation extends BaseAugmentation {
|
|
|
310
311
|
super();
|
|
311
312
|
this.name = 'server-search-activation';
|
|
312
313
|
this.timing = 'after';
|
|
314
|
+
this.metadata = 'readonly'; // Reads metadata for server activation
|
|
313
315
|
this.operations = ['search', 'addNoun'];
|
|
314
316
|
this.priority = 20;
|
|
315
317
|
this.conduitAugmentation = null;
|