@soulcraft/brainy 6.2.9 → 6.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/CHANGELOG.md +21 -0
- package/dist/brainy.d.ts +55 -0
- package/dist/brainy.js +104 -7
- package/dist/graph/graphAdjacencyIndex.d.ts +7 -0
- package/dist/graph/graphAdjacencyIndex.js +42 -0
- package/dist/storage/baseStorage.d.ts +7 -0
- package/dist/storage/baseStorage.js +31 -38
- package/dist/versioning/VersionIndex.d.ts +42 -47
- package/dist/versioning/VersionIndex.js +141 -166
- package/dist/versioning/VersionManager.d.ts +12 -6
- package/dist/versioning/VersionManager.js +26 -8
- package/dist/versioning/VersionStorage.d.ts +25 -15
- package/dist/versioning/VersionStorage.js +49 -65
- package/dist/vfs/PathResolver.d.ts +6 -0
- package/dist/vfs/PathResolver.js +20 -0
- package/dist/vfs/semantic/SemanticPathResolver.d.ts +6 -0
- package/dist/vfs/semantic/SemanticPathResolver.js +11 -0
- package/package.json +1 -1
- package/dist/augmentations/KnowledgeAugmentation.d.ts +0 -40
- package/dist/augmentations/KnowledgeAugmentation.js +0 -251
- package/dist/importManager.d.ts +0 -78
- package/dist/importManager.js +0 -267
- package/dist/query/typeInference.d.ts +0 -158
- package/dist/query/typeInference.js +0 -760
- package/dist/storage/adapters/typeAwareStorageAdapter.d.ts +0 -252
- package/dist/storage/adapters/typeAwareStorageAdapter.js +0 -814
- package/dist/types/brainyDataInterface.d.ts +0 -52
- package/dist/types/brainyDataInterface.js +0 -10
- package/dist/vfs/ConceptSystem.d.ts +0 -203
- package/dist/vfs/ConceptSystem.js +0 -545
- package/dist/vfs/EntityManager.d.ts +0 -75
- package/dist/vfs/EntityManager.js +0 -216
- package/dist/vfs/EventRecorder.d.ts +0 -84
- package/dist/vfs/EventRecorder.js +0 -269
- package/dist/vfs/GitBridge.d.ts +0 -167
- package/dist/vfs/GitBridge.js +0 -537
- package/dist/vfs/KnowledgeLayer.d.ts +0 -35
- package/dist/vfs/KnowledgeLayer.js +0 -443
- package/dist/vfs/PersistentEntitySystem.d.ts +0 -165
- package/dist/vfs/PersistentEntitySystem.js +0 -503
- package/dist/vfs/SemanticVersioning.d.ts +0 -105
- package/dist/vfs/SemanticVersioning.js +0 -309
|
@@ -1,545 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Universal Concept System for VFS
|
|
3
|
-
*
|
|
4
|
-
* Manages concepts that transcend files and exist independently
|
|
5
|
-
* Ideas that can be linked to multiple manifestations across domains
|
|
6
|
-
* PRODUCTION-READY: Real implementation using Brainy
|
|
7
|
-
*/
|
|
8
|
-
import { NounType, VerbType } from '../types/graphTypes.js';
|
|
9
|
-
import { cosineDistance } from '../utils/distance.js';
|
|
10
|
-
import { v4 as uuidv4 } from '../universal/uuid.js';
|
|
11
|
-
import { EntityManager } from './EntityManager.js';
|
|
12
|
-
/**
|
|
13
|
-
* Universal Concept System
|
|
14
|
-
*
|
|
15
|
-
* Manages concepts that exist independently of any specific file or context
|
|
16
|
-
* Examples:
|
|
17
|
-
* - "Authentication" concept appearing in docs, code, tests
|
|
18
|
-
* - "Customer Journey" concept in marketing, UX, analytics
|
|
19
|
-
* - "Dependency Injection" pattern across multiple codebases
|
|
20
|
-
* - "Sustainability" theme in various research papers
|
|
21
|
-
*/
|
|
22
|
-
export class ConceptSystem extends EntityManager {
|
|
23
|
-
constructor(brain, config) {
|
|
24
|
-
super(brain, 'vfs-concept');
|
|
25
|
-
this.conceptCache = new Map();
|
|
26
|
-
this.config = {
|
|
27
|
-
autoLink: config?.autoLink ?? false,
|
|
28
|
-
similarityThreshold: config?.similarityThreshold ?? 0.7,
|
|
29
|
-
maxManifestations: config?.maxManifestations ?? 1000,
|
|
30
|
-
strengthDecay: config?.strengthDecay ?? 0.95 // 5% decay over time
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Create a new universal concept
|
|
35
|
-
*/
|
|
36
|
-
async createConcept(concept) {
|
|
37
|
-
const conceptId = uuidv4();
|
|
38
|
-
const timestamp = Date.now();
|
|
39
|
-
const universalConcept = {
|
|
40
|
-
id: conceptId,
|
|
41
|
-
name: concept.name,
|
|
42
|
-
description: concept.description,
|
|
43
|
-
domain: concept.domain,
|
|
44
|
-
category: concept.category,
|
|
45
|
-
keywords: concept.keywords,
|
|
46
|
-
strength: concept.strength,
|
|
47
|
-
metadata: concept.metadata || {},
|
|
48
|
-
created: timestamp,
|
|
49
|
-
lastUpdated: timestamp,
|
|
50
|
-
version: 1,
|
|
51
|
-
links: [],
|
|
52
|
-
manifestations: [],
|
|
53
|
-
conceptType: 'universal' // Add conceptType for querying
|
|
54
|
-
};
|
|
55
|
-
// Generate embedding for concept
|
|
56
|
-
let embedding;
|
|
57
|
-
try {
|
|
58
|
-
embedding = await this.generateConceptEmbedding(universalConcept);
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
console.warn('Failed to generate concept embedding:', error);
|
|
62
|
-
}
|
|
63
|
-
// Store concept using EntityManager
|
|
64
|
-
await this.storeEntity(universalConcept, NounType.Concept, embedding, Buffer.from(JSON.stringify(universalConcept)));
|
|
65
|
-
// Auto-link to similar concepts if enabled
|
|
66
|
-
if (this.config.autoLink) {
|
|
67
|
-
await this.autoLinkConcept(conceptId);
|
|
68
|
-
}
|
|
69
|
-
// Update cache
|
|
70
|
-
this.conceptCache.set(conceptId, universalConcept);
|
|
71
|
-
return conceptId; // Return domain ID, not Brainy ID
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Find concepts by various criteria
|
|
75
|
-
*/
|
|
76
|
-
async findConcepts(query) {
|
|
77
|
-
const searchQuery = {
|
|
78
|
-
conceptType: 'universal',
|
|
79
|
-
system: 'vfs-concept'
|
|
80
|
-
};
|
|
81
|
-
// Direct attribute matching
|
|
82
|
-
if (query.name)
|
|
83
|
-
searchQuery.name = query.name;
|
|
84
|
-
if (query.domain)
|
|
85
|
-
searchQuery.domain = query.domain;
|
|
86
|
-
if (query.category)
|
|
87
|
-
searchQuery.category = query.category;
|
|
88
|
-
// Keyword matching
|
|
89
|
-
if (query.keywords && query.keywords.length > 0) {
|
|
90
|
-
searchQuery.keywords = { $in: query.keywords };
|
|
91
|
-
}
|
|
92
|
-
// File manifestation search
|
|
93
|
-
if (query.manifestedIn) {
|
|
94
|
-
// Find concepts that have manifestations in this file
|
|
95
|
-
const manifestationResults = await this.findEntities({
|
|
96
|
-
filePath: query.manifestedIn,
|
|
97
|
-
eventType: 'concept-manifestation'
|
|
98
|
-
}, NounType.Event, 1000);
|
|
99
|
-
const conceptIds = manifestationResults.map(m => m.conceptId);
|
|
100
|
-
if (conceptIds.length > 0) {
|
|
101
|
-
searchQuery.id = { $in: conceptIds };
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
return []; // No concepts found in this file
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// Search using EntityManager
|
|
108
|
-
const results = await this.findEntities(searchQuery, NounType.Concept, 1000);
|
|
109
|
-
// If searching for similar concepts, use vector similarity
|
|
110
|
-
if (query.similar) {
|
|
111
|
-
try {
|
|
112
|
-
const queryEmbedding = await this.generateTextEmbedding(query.similar);
|
|
113
|
-
if (queryEmbedding) {
|
|
114
|
-
// Get all concepts and rank by similarity
|
|
115
|
-
const allConcepts = await this.findEntities({ conceptType: 'universal' }, NounType.Concept, 10000);
|
|
116
|
-
// For similarity search, we need to get the actual vector data from Brainy
|
|
117
|
-
const conceptsWithVectors = [];
|
|
118
|
-
for (const concept of allConcepts) {
|
|
119
|
-
if (concept.brainyId) {
|
|
120
|
-
const brainyEntity = await this.brain.get(concept.brainyId);
|
|
121
|
-
if (brainyEntity?.vector && brainyEntity.vector.length > 0) {
|
|
122
|
-
conceptsWithVectors.push({
|
|
123
|
-
concept,
|
|
124
|
-
vector: brainyEntity.vector
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
const withSimilarity = conceptsWithVectors
|
|
130
|
-
.map(c => ({
|
|
131
|
-
concept: c.concept,
|
|
132
|
-
similarity: 1 - cosineDistance(queryEmbedding, c.vector)
|
|
133
|
-
}))
|
|
134
|
-
.filter(s => s.similarity > this.config.similarityThreshold)
|
|
135
|
-
.sort((a, b) => b.similarity - a.similarity);
|
|
136
|
-
return withSimilarity.map(s => s.concept);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
catch (error) {
|
|
140
|
-
console.warn('Failed to perform concept similarity search:', error);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return results;
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Link two concepts together
|
|
147
|
-
*/
|
|
148
|
-
async linkConcept(fromConceptId, toConceptId, relationship, options) {
|
|
149
|
-
const linkId = uuidv4();
|
|
150
|
-
const fromConcept = await this.getConcept(fromConceptId);
|
|
151
|
-
const toConcept = await this.getConcept(toConceptId);
|
|
152
|
-
if (!fromConcept || !toConcept) {
|
|
153
|
-
throw new Error('One or both concepts not found');
|
|
154
|
-
}
|
|
155
|
-
// Create link
|
|
156
|
-
const link = {
|
|
157
|
-
id: linkId,
|
|
158
|
-
targetConceptId: toConceptId,
|
|
159
|
-
relationship,
|
|
160
|
-
strength: options?.strength ?? 0.8,
|
|
161
|
-
context: options?.context,
|
|
162
|
-
bidirectional: options?.bidirectional ?? false
|
|
163
|
-
};
|
|
164
|
-
// Add link to source concept
|
|
165
|
-
fromConcept.links.push(link);
|
|
166
|
-
fromConcept.lastUpdated = Date.now();
|
|
167
|
-
await this.updateConcept(fromConcept);
|
|
168
|
-
// Add bidirectional link if specified
|
|
169
|
-
if (link.bidirectional) {
|
|
170
|
-
const reverseRelationship = this.getReverseRelationship(relationship);
|
|
171
|
-
const reverseLink = {
|
|
172
|
-
id: uuidv4(),
|
|
173
|
-
targetConceptId: fromConceptId,
|
|
174
|
-
relationship: reverseRelationship,
|
|
175
|
-
strength: link.strength,
|
|
176
|
-
context: link.context,
|
|
177
|
-
bidirectional: true
|
|
178
|
-
};
|
|
179
|
-
toConcept.links.push(reverseLink);
|
|
180
|
-
toConcept.lastUpdated = Date.now();
|
|
181
|
-
await this.updateConcept(toConcept);
|
|
182
|
-
}
|
|
183
|
-
// Create relationship using EntityManager
|
|
184
|
-
await this.createRelationship(fromConceptId, toConceptId, this.getVerbType(relationship), {
|
|
185
|
-
strength: link.strength,
|
|
186
|
-
context: link.context,
|
|
187
|
-
bidirectional: link.bidirectional
|
|
188
|
-
});
|
|
189
|
-
return linkId;
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Record a manifestation of a concept in a file
|
|
193
|
-
*/
|
|
194
|
-
async recordManifestation(conceptId, filePath, context, form, options) {
|
|
195
|
-
const concept = await this.getConcept(conceptId);
|
|
196
|
-
if (!concept) {
|
|
197
|
-
throw new Error(`Concept ${conceptId} not found`);
|
|
198
|
-
}
|
|
199
|
-
const manifestationId = uuidv4();
|
|
200
|
-
const timestamp = Date.now();
|
|
201
|
-
const manifestation = {
|
|
202
|
-
id: manifestationId,
|
|
203
|
-
conceptId,
|
|
204
|
-
filePath,
|
|
205
|
-
context,
|
|
206
|
-
form,
|
|
207
|
-
position: options?.position,
|
|
208
|
-
confidence: options?.confidence ?? 1.0,
|
|
209
|
-
timestamp,
|
|
210
|
-
extractedBy: options?.extractedBy ?? 'manual'
|
|
211
|
-
};
|
|
212
|
-
// Store manifestation as managed entity (with eventType for manifestations)
|
|
213
|
-
const manifestationWithEventType = {
|
|
214
|
-
...manifestation,
|
|
215
|
-
eventType: 'concept-manifestation'
|
|
216
|
-
};
|
|
217
|
-
await this.storeEntity(manifestationWithEventType, NounType.Event, undefined, Buffer.from(context));
|
|
218
|
-
// Create relationship to concept using EntityManager
|
|
219
|
-
await this.createRelationship(manifestationId, conceptId, VerbType.Implements);
|
|
220
|
-
// Update concept with new manifestation
|
|
221
|
-
concept.manifestations.push(manifestation);
|
|
222
|
-
concept.lastUpdated = timestamp;
|
|
223
|
-
// Update concept strength based on manifestations
|
|
224
|
-
concept.strength = Math.min(1.0, concept.strength + 0.1);
|
|
225
|
-
// Prune old manifestations if needed
|
|
226
|
-
if (concept.manifestations.length > this.config.maxManifestations) {
|
|
227
|
-
concept.manifestations = concept.manifestations
|
|
228
|
-
.sort((a, b) => b.timestamp - a.timestamp)
|
|
229
|
-
.slice(0, this.config.maxManifestations);
|
|
230
|
-
}
|
|
231
|
-
// Update stored concept
|
|
232
|
-
await this.updateConcept(concept);
|
|
233
|
-
return manifestationId;
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Extract and link concepts from content
|
|
237
|
-
*/
|
|
238
|
-
async extractAndLinkConcepts(filePath, content) {
|
|
239
|
-
if (!this.config.autoLink) {
|
|
240
|
-
return [];
|
|
241
|
-
}
|
|
242
|
-
const text = content.toString('utf8');
|
|
243
|
-
const extractedConcepts = [];
|
|
244
|
-
// Simple concept extraction patterns
|
|
245
|
-
// In production, this would use advanced NLP/AI models
|
|
246
|
-
const conceptPatterns = [
|
|
247
|
-
// Technical concepts
|
|
248
|
-
/\b(authentication|authorization|validation|encryption|caching|logging|monitoring)\b/gi,
|
|
249
|
-
// Business concepts
|
|
250
|
-
/\b(customer\s+journey|user\s+experience|business\s+logic|revenue\s+model)\b/gi,
|
|
251
|
-
// Design patterns
|
|
252
|
-
/\b(singleton|factory|observer|strategy|adapter|decorator)\b/gi,
|
|
253
|
-
// General concepts
|
|
254
|
-
/\b(security|performance|scalability|maintainability|reliability)\b/gi
|
|
255
|
-
];
|
|
256
|
-
for (const pattern of conceptPatterns) {
|
|
257
|
-
const matches = text.matchAll(pattern);
|
|
258
|
-
for (const match of matches) {
|
|
259
|
-
const conceptName = match[0].toLowerCase();
|
|
260
|
-
const context = this.extractContext(text, match.index || 0);
|
|
261
|
-
// Find or create concept
|
|
262
|
-
let concepts = await this.findConcepts({ name: conceptName });
|
|
263
|
-
let conceptId;
|
|
264
|
-
if (concepts.length === 0) {
|
|
265
|
-
// Create new concept
|
|
266
|
-
conceptId = await this.createConcept({
|
|
267
|
-
name: conceptName,
|
|
268
|
-
domain: this.detectDomain(conceptName, text),
|
|
269
|
-
category: this.detectCategory(conceptName),
|
|
270
|
-
keywords: [conceptName],
|
|
271
|
-
strength: 0.5,
|
|
272
|
-
metadata: {}
|
|
273
|
-
});
|
|
274
|
-
extractedConcepts.push(conceptId);
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
conceptId = concepts[0].id;
|
|
278
|
-
}
|
|
279
|
-
// Record manifestation
|
|
280
|
-
await this.recordManifestation(conceptId, filePath, context, this.detectManifestationForm(context), {
|
|
281
|
-
confidence: 0.8,
|
|
282
|
-
extractedBy: 'auto'
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
return extractedConcepts;
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Get concept graph for visualization
|
|
290
|
-
*/
|
|
291
|
-
async getConceptGraph(options) {
|
|
292
|
-
const query = {
|
|
293
|
-
conceptType: 'universal',
|
|
294
|
-
system: 'vfs-concept'
|
|
295
|
-
};
|
|
296
|
-
if (options?.domain) {
|
|
297
|
-
query.domain = options.domain;
|
|
298
|
-
}
|
|
299
|
-
if (options?.minStrength) {
|
|
300
|
-
query.strength = { $gte: options.minStrength };
|
|
301
|
-
}
|
|
302
|
-
const concepts = await this.findEntities(query, NounType.Concept, options?.maxConcepts || 1000);
|
|
303
|
-
// Build graph structure
|
|
304
|
-
const graphConcepts = concepts.map(c => ({
|
|
305
|
-
id: c.id,
|
|
306
|
-
name: c.name,
|
|
307
|
-
domain: c.domain,
|
|
308
|
-
strength: c.strength,
|
|
309
|
-
manifestationCount: c.manifestations.length
|
|
310
|
-
}));
|
|
311
|
-
const graphLinks = [];
|
|
312
|
-
for (const concept of concepts) {
|
|
313
|
-
for (const link of concept.links) {
|
|
314
|
-
// Only include links to concepts in our result set
|
|
315
|
-
if (concepts.find(c => c.id === link.targetConceptId)) {
|
|
316
|
-
graphLinks.push({
|
|
317
|
-
source: concept.id,
|
|
318
|
-
target: link.targetConceptId,
|
|
319
|
-
relationship: link.relationship,
|
|
320
|
-
strength: link.strength
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
return {
|
|
326
|
-
concepts: graphConcepts,
|
|
327
|
-
links: graphLinks
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* Find appearances of a concept
|
|
332
|
-
*/
|
|
333
|
-
async findAppearances(conceptId, options) {
|
|
334
|
-
const query = {
|
|
335
|
-
conceptId,
|
|
336
|
-
eventType: 'concept-manifestation',
|
|
337
|
-
system: 'vfs-concept'
|
|
338
|
-
};
|
|
339
|
-
if (options?.filePath) {
|
|
340
|
-
query.filePath = options.filePath;
|
|
341
|
-
}
|
|
342
|
-
if (options?.form) {
|
|
343
|
-
query.form = options.form;
|
|
344
|
-
}
|
|
345
|
-
if (options?.minConfidence) {
|
|
346
|
-
query.confidence = { $gte: options.minConfidence };
|
|
347
|
-
}
|
|
348
|
-
const manifestations = await this.findEntities(query, NounType.Event, options?.limit || 1000);
|
|
349
|
-
return manifestations.sort((a, b) => b.timestamp - a.timestamp);
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Auto-link concept to similar concepts
|
|
353
|
-
*/
|
|
354
|
-
async autoLinkConcept(conceptId) {
|
|
355
|
-
const concept = await this.getConcept(conceptId);
|
|
356
|
-
if (!concept)
|
|
357
|
-
return;
|
|
358
|
-
// Find similar concepts
|
|
359
|
-
const similar = await this.findConcepts({
|
|
360
|
-
similar: concept.name + ' ' + (concept.description || '')
|
|
361
|
-
});
|
|
362
|
-
for (const similarConcept of similar) {
|
|
363
|
-
if (similarConcept.id === conceptId)
|
|
364
|
-
continue;
|
|
365
|
-
// Calculate relationship strength based on similarity
|
|
366
|
-
const strength = await this.calculateConceptSimilarity(concept, similarConcept);
|
|
367
|
-
if (strength > this.config.similarityThreshold) {
|
|
368
|
-
await this.linkConcept(conceptId, similarConcept.id, 'related', { strength, bidirectional: true });
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* Get concept by ID
|
|
374
|
-
*/
|
|
375
|
-
async getConcept(conceptId) {
|
|
376
|
-
// Check cache first
|
|
377
|
-
if (this.conceptCache.has(conceptId)) {
|
|
378
|
-
return this.conceptCache.get(conceptId);
|
|
379
|
-
}
|
|
380
|
-
// Query using EntityManager
|
|
381
|
-
const concept = await this.getEntity(conceptId);
|
|
382
|
-
if (concept) {
|
|
383
|
-
this.conceptCache.set(conceptId, concept);
|
|
384
|
-
}
|
|
385
|
-
return concept;
|
|
386
|
-
}
|
|
387
|
-
/**
|
|
388
|
-
* Update stored concept
|
|
389
|
-
*/
|
|
390
|
-
async updateConcept(concept) {
|
|
391
|
-
// Add conceptType metadata before updating
|
|
392
|
-
concept.conceptType = 'universal';
|
|
393
|
-
// Update using EntityManager
|
|
394
|
-
await this.updateEntity(concept);
|
|
395
|
-
// Update cache
|
|
396
|
-
this.conceptCache.set(concept.id, concept);
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Calculate similarity between two concepts
|
|
400
|
-
*/
|
|
401
|
-
async calculateConceptSimilarity(concept1, concept2) {
|
|
402
|
-
// Simple similarity calculation
|
|
403
|
-
let similarity = 0;
|
|
404
|
-
// Domain similarity
|
|
405
|
-
if (concept1.domain === concept2.domain)
|
|
406
|
-
similarity += 0.3;
|
|
407
|
-
// Category similarity
|
|
408
|
-
if (concept1.category === concept2.category)
|
|
409
|
-
similarity += 0.2;
|
|
410
|
-
// Keyword overlap
|
|
411
|
-
const commonKeywords = concept1.keywords.filter(k => concept2.keywords.includes(k));
|
|
412
|
-
similarity += (commonKeywords.length / Math.max(concept1.keywords.length, concept2.keywords.length)) * 0.3;
|
|
413
|
-
// Name similarity (simple string comparison)
|
|
414
|
-
const nameWords1 = concept1.name.toLowerCase().split(/\s+/);
|
|
415
|
-
const nameWords2 = concept2.name.toLowerCase().split(/\s+/);
|
|
416
|
-
const commonWords = nameWords1.filter(w => nameWords2.includes(w));
|
|
417
|
-
similarity += (commonWords.length / Math.max(nameWords1.length, nameWords2.length)) * 0.2;
|
|
418
|
-
return Math.min(1.0, similarity);
|
|
419
|
-
}
|
|
420
|
-
/**
|
|
421
|
-
* Generate embedding for concept
|
|
422
|
-
*/
|
|
423
|
-
async generateConceptEmbedding(concept) {
|
|
424
|
-
try {
|
|
425
|
-
const text = [
|
|
426
|
-
concept.name,
|
|
427
|
-
concept.description || '',
|
|
428
|
-
concept.domain,
|
|
429
|
-
concept.category,
|
|
430
|
-
...(Array.isArray(concept.keywords) ? concept.keywords : [])
|
|
431
|
-
].join(' ');
|
|
432
|
-
return await this.generateTextEmbedding(text);
|
|
433
|
-
}
|
|
434
|
-
catch (error) {
|
|
435
|
-
console.error('Failed to generate concept embedding:', error);
|
|
436
|
-
return undefined;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
|
-
* Generate embedding for text
|
|
441
|
-
*/
|
|
442
|
-
async generateTextEmbedding(text) {
|
|
443
|
-
try {
|
|
444
|
-
// Generate embedding using Brainy's embed method
|
|
445
|
-
const vector = await this.brain.embed(text);
|
|
446
|
-
return vector;
|
|
447
|
-
}
|
|
448
|
-
catch (error) {
|
|
449
|
-
console.debug('Failed to generate embedding:', error);
|
|
450
|
-
return undefined;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
/**
|
|
454
|
-
* Get reverse relationship type
|
|
455
|
-
*/
|
|
456
|
-
getReverseRelationship(relationship) {
|
|
457
|
-
const reverseMap = {
|
|
458
|
-
'extends': 'extended-by',
|
|
459
|
-
'implements': 'implemented-by',
|
|
460
|
-
'uses': 'used-by',
|
|
461
|
-
'opposite': 'opposite',
|
|
462
|
-
'related': 'related',
|
|
463
|
-
'contains': 'part-of',
|
|
464
|
-
'part-of': 'contains'
|
|
465
|
-
};
|
|
466
|
-
return reverseMap[relationship] || 'related';
|
|
467
|
-
}
|
|
468
|
-
/**
|
|
469
|
-
* Map concept relationship to VerbType
|
|
470
|
-
*/
|
|
471
|
-
getVerbType(relationship) {
|
|
472
|
-
const verbMap = {
|
|
473
|
-
'extends': VerbType.Extends,
|
|
474
|
-
'implements': VerbType.Implements,
|
|
475
|
-
'uses': VerbType.Uses,
|
|
476
|
-
'opposite': VerbType.Conflicts,
|
|
477
|
-
'related': VerbType.RelatedTo,
|
|
478
|
-
'contains': VerbType.Contains,
|
|
479
|
-
'part-of': VerbType.PartOf
|
|
480
|
-
};
|
|
481
|
-
return verbMap[relationship] || VerbType.RelatedTo;
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* Detect concept domain from context
|
|
485
|
-
*/
|
|
486
|
-
detectDomain(conceptName, context) {
|
|
487
|
-
if (/import|export|function|class|const|var|let/.test(context))
|
|
488
|
-
return 'technical';
|
|
489
|
-
if (/customer|user|business|revenue|market/.test(context))
|
|
490
|
-
return 'business';
|
|
491
|
-
if (/design|pattern|architecture/.test(context))
|
|
492
|
-
return 'design';
|
|
493
|
-
if (/research|study|analysis/.test(context))
|
|
494
|
-
return 'academic';
|
|
495
|
-
return 'general';
|
|
496
|
-
}
|
|
497
|
-
/**
|
|
498
|
-
* Detect concept category
|
|
499
|
-
*/
|
|
500
|
-
detectCategory(conceptName) {
|
|
501
|
-
if (/pattern|strategy|factory|singleton/.test(conceptName))
|
|
502
|
-
return 'pattern';
|
|
503
|
-
if (/principle|rule|law/.test(conceptName))
|
|
504
|
-
return 'principle';
|
|
505
|
-
if (/method|approach|technique/.test(conceptName))
|
|
506
|
-
return 'method';
|
|
507
|
-
if (/entity|object|model/.test(conceptName))
|
|
508
|
-
return 'entity';
|
|
509
|
-
return 'concept';
|
|
510
|
-
}
|
|
511
|
-
/**
|
|
512
|
-
* Detect manifestation form from context
|
|
513
|
-
*/
|
|
514
|
-
detectManifestationForm(context) {
|
|
515
|
-
if (context.includes('definition') || context.includes('is defined as'))
|
|
516
|
-
return 'definition';
|
|
517
|
-
if (context.includes('example') || context.includes('for instance'))
|
|
518
|
-
return 'example';
|
|
519
|
-
if (context.includes('implements') || context.includes('function'))
|
|
520
|
-
return 'implementation';
|
|
521
|
-
if (context.includes('discussed') || context.includes('explains'))
|
|
522
|
-
return 'discussion';
|
|
523
|
-
return 'usage';
|
|
524
|
-
}
|
|
525
|
-
/**
|
|
526
|
-
* Extract context around a position
|
|
527
|
-
*/
|
|
528
|
-
extractContext(text, position, radius = 150) {
|
|
529
|
-
const start = Math.max(0, position - radius);
|
|
530
|
-
const end = Math.min(text.length, position + radius);
|
|
531
|
-
return text.slice(start, end);
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
* Clear concept cache
|
|
535
|
-
*/
|
|
536
|
-
clearCache(conceptId) {
|
|
537
|
-
if (conceptId) {
|
|
538
|
-
this.conceptCache.delete(conceptId);
|
|
539
|
-
}
|
|
540
|
-
else {
|
|
541
|
-
this.conceptCache.clear();
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
//# sourceMappingURL=ConceptSystem.js.map
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* EntityManager Base Class
|
|
3
|
-
*
|
|
4
|
-
* Provides standardized entity ID management for all Knowledge Layer components
|
|
5
|
-
* Solves the root cause of ID mismatch issues by establishing clear patterns
|
|
6
|
-
*/
|
|
7
|
-
import { Brainy } from '../brainy.js';
|
|
8
|
-
import { NounType } from '../types/graphTypes.js';
|
|
9
|
-
/**
|
|
10
|
-
* Standard entity structure used by all Knowledge Layer components
|
|
11
|
-
*/
|
|
12
|
-
export interface ManagedEntity {
|
|
13
|
-
/** Domain-specific ID (for external references) */
|
|
14
|
-
id: string;
|
|
15
|
-
/** The actual Brainy entity ID (for internal operations) */
|
|
16
|
-
brainyId?: string;
|
|
17
|
-
/** Entity metadata */
|
|
18
|
-
[key: string]: any;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* EntityManager Base Class
|
|
22
|
-
*
|
|
23
|
-
* All Knowledge Layer components should extend this to get standardized:
|
|
24
|
-
* - Entity storage and retrieval
|
|
25
|
-
* - ID management and mapping
|
|
26
|
-
* - Query patterns
|
|
27
|
-
* - Relationship creation
|
|
28
|
-
*/
|
|
29
|
-
export declare abstract class EntityManager {
|
|
30
|
-
protected brain: Brainy;
|
|
31
|
-
protected systemName: string;
|
|
32
|
-
private idMappings;
|
|
33
|
-
private brainyToMappings;
|
|
34
|
-
constructor(brain: Brainy, systemName: string);
|
|
35
|
-
/**
|
|
36
|
-
* Store an entity with proper ID management
|
|
37
|
-
*/
|
|
38
|
-
protected storeEntity<T extends ManagedEntity>(entity: T, nounType: NounType, embedding?: number[], data?: any): Promise<string>;
|
|
39
|
-
/**
|
|
40
|
-
* Update an existing entity
|
|
41
|
-
*/
|
|
42
|
-
protected updateEntity<T extends ManagedEntity>(entity: T, embedding?: number[]): Promise<void>;
|
|
43
|
-
/**
|
|
44
|
-
* Retrieve entity by domain ID
|
|
45
|
-
*/
|
|
46
|
-
protected getEntity<T extends ManagedEntity>(domainId: string): Promise<T | null>;
|
|
47
|
-
/**
|
|
48
|
-
* Find entities by metadata criteria
|
|
49
|
-
*/
|
|
50
|
-
protected findEntities<T extends ManagedEntity>(criteria: Record<string, any>, nounType?: NounType, limit?: number): Promise<T[]>;
|
|
51
|
-
/**
|
|
52
|
-
* Create relationship between entities using proper Brainy IDs
|
|
53
|
-
*/
|
|
54
|
-
protected createRelationship(fromDomainId: string, toDomainId: string, relationshipType: any, metadata?: Record<string, any>): Promise<void>;
|
|
55
|
-
/**
|
|
56
|
-
* Get Brainy ID for a domain ID
|
|
57
|
-
*/
|
|
58
|
-
protected getBrainyId(domainId: string): Promise<string | null>;
|
|
59
|
-
/**
|
|
60
|
-
* Get domain ID for a Brainy ID
|
|
61
|
-
*/
|
|
62
|
-
protected getDomainId(brainyId: string): string | null;
|
|
63
|
-
/**
|
|
64
|
-
* Delete entity by domain ID
|
|
65
|
-
*/
|
|
66
|
-
protected deleteEntity(domainId: string): Promise<void>;
|
|
67
|
-
/**
|
|
68
|
-
* Clear ID mapping cache (useful for tests)
|
|
69
|
-
*/
|
|
70
|
-
protected clearMappingCache(): void;
|
|
71
|
-
/**
|
|
72
|
-
* Batch load mappings for performance
|
|
73
|
-
*/
|
|
74
|
-
protected loadMappings(domainIds: string[]): Promise<void>;
|
|
75
|
-
}
|