agentdb 3.0.0-alpha.11 → 3.0.0-alpha.13
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/src/backends/graph/GraphDatabaseAdapter.d.ts +54 -0
- package/dist/src/backends/graph/GraphDatabaseAdapter.d.ts.map +1 -1
- package/dist/src/backends/graph/GraphDatabaseAdapter.js +125 -0
- package/dist/src/backends/graph/GraphDatabaseAdapter.js.map +1 -1
- package/dist/src/cli/agentdb-cli.js +0 -0
- package/dist/src/controllers/ReflexionMemory.d.ts +50 -0
- package/dist/src/controllers/ReflexionMemory.d.ts.map +1 -1
- package/dist/src/controllers/ReflexionMemory.js +258 -0
- package/dist/src/controllers/ReflexionMemory.js.map +1 -1
- package/dist/src/controllers/index.d.ts +2 -0
- package/dist/src/controllers/index.d.ts.map +1 -1
- package/dist/src/controllers/index.js +2 -0
- package/dist/src/controllers/index.js.map +1 -1
- package/dist/src/controllers/prerequisites.d.ts +76 -0
- package/dist/src/controllers/prerequisites.d.ts.map +1 -0
- package/dist/src/controllers/prerequisites.js +235 -0
- package/dist/src/controllers/prerequisites.js.map +1 -0
- package/dist/src/db-fallback.d.ts.map +1 -1
- package/dist/src/db-fallback.js +55 -45
- package/dist/src/db-fallback.js.map +1 -1
- package/package.json +1 -1
- package/dist/schemas/frontier-schema.sql +0 -378
- package/dist/schemas/schema.sql +0 -382
- package/dist/src/backends/index.cjs +0 -6
- package/dist/src/backends/ruvector/GuardedVectorBackend.d.ts +0 -93
- package/dist/src/backends/ruvector/GuardedVectorBackend.d.ts.map +0 -1
- package/dist/src/backends/ruvector/GuardedVectorBackend.js +0 -182
- package/dist/src/backends/ruvector/GuardedVectorBackend.js.map +0 -1
- package/dist/src/consensus/RaftConsensus.d.ts +0 -220
- package/dist/src/consensus/RaftConsensus.d.ts.map +0 -1
- package/dist/src/consensus/RaftConsensus.js +0 -762
- package/dist/src/consensus/RaftConsensus.js.map +0 -1
- package/dist/src/controllers/HierarchicalMemory.d.ts +0 -197
- package/dist/src/controllers/HierarchicalMemory.d.ts.map +0 -1
- package/dist/src/controllers/HierarchicalMemory.js +0 -519
- package/dist/src/controllers/HierarchicalMemory.js.map +0 -1
- package/dist/src/controllers/MemoryConsolidation.d.ts +0 -142
- package/dist/src/controllers/MemoryConsolidation.d.ts.map +0 -1
- package/dist/src/controllers/MemoryConsolidation.js +0 -479
- package/dist/src/controllers/MemoryConsolidation.js.map +0 -1
- package/dist/src/controllers/QUICConnection.d.ts +0 -122
- package/dist/src/controllers/QUICConnection.d.ts.map +0 -1
- package/dist/src/controllers/QUICConnection.js +0 -329
- package/dist/src/controllers/QUICConnection.js.map +0 -1
- package/dist/src/controllers/QUICConnectionPool.d.ts +0 -83
- package/dist/src/controllers/QUICConnectionPool.d.ts.map +0 -1
- package/dist/src/controllers/QUICConnectionPool.js +0 -256
- package/dist/src/controllers/QUICConnectionPool.js.map +0 -1
- package/dist/src/controllers/QUICStreamManager.d.ts +0 -114
- package/dist/src/controllers/QUICStreamManager.d.ts.map +0 -1
- package/dist/src/controllers/QUICStreamManager.js +0 -267
- package/dist/src/controllers/QUICStreamManager.js.map +0 -1
- package/dist/src/controllers/StreamingEmbeddingService.d.ts +0 -82
- package/dist/src/controllers/StreamingEmbeddingService.d.ts.map +0 -1
- package/dist/src/controllers/StreamingEmbeddingService.js +0 -243
- package/dist/src/controllers/StreamingEmbeddingService.js.map +0 -1
- package/dist/src/controllers/index.cjs +0 -6
- package/dist/src/coordination/MultiDatabaseCoordinator.d.ts +0 -348
- package/dist/src/coordination/MultiDatabaseCoordinator.d.ts.map +0 -1
- package/dist/src/coordination/MultiDatabaseCoordinator.js +0 -803
- package/dist/src/coordination/MultiDatabaseCoordinator.js.map +0 -1
- package/dist/src/coordination/index.d.ts +0 -10
- package/dist/src/coordination/index.d.ts.map +0 -1
- package/dist/src/coordination/index.js +0 -10
- package/dist/src/coordination/index.js.map +0 -1
- package/dist/src/index.cjs +0 -6
- package/dist/src/optimizations/RVFOptimizer.d.ts +0 -226
- package/dist/src/optimizations/RVFOptimizer.d.ts.map +0 -1
- package/dist/src/optimizations/RVFOptimizer.js +0 -541
- package/dist/src/optimizations/RVFOptimizer.js.map +0 -1
- package/dist/src/security/AttestationLog.d.ts +0 -70
- package/dist/src/security/AttestationLog.d.ts.map +0 -1
- package/dist/src/security/AttestationLog.js +0 -174
- package/dist/src/security/AttestationLog.js.map +0 -1
- package/dist/src/security/MutationGuard.d.ts +0 -83
- package/dist/src/security/MutationGuard.d.ts.map +0 -1
- package/dist/src/security/MutationGuard.js +0 -364
- package/dist/src/security/MutationGuard.js.map +0 -1
- package/dist/src/security/index.cjs +0 -6
- package/dist/src/security/index.d.ts +0 -15
- package/dist/src/security/index.d.ts.map +0 -1
- package/dist/src/security/index.js +0 -18
- package/dist/src/security/index.js.map +0 -1
- package/dist/src/services/GNNService.d.ts +0 -173
- package/dist/src/services/GNNService.d.ts.map +0 -1
- package/dist/src/services/GNNService.js +0 -639
- package/dist/src/services/GNNService.js.map +0 -1
- package/dist/src/services/GraphTransformerService.d.ts +0 -80
- package/dist/src/services/GraphTransformerService.d.ts.map +0 -1
- package/dist/src/services/GraphTransformerService.js +0 -369
- package/dist/src/services/GraphTransformerService.js.map +0 -1
- package/dist/src/services/SemanticRouter.d.ts +0 -83
- package/dist/src/services/SemanticRouter.d.ts.map +0 -1
- package/dist/src/services/SemanticRouter.js +0 -160
- package/dist/src/services/SemanticRouter.js.map +0 -1
- package/dist/src/services/SonaTrajectoryService.d.ts +0 -224
- package/dist/src/services/SonaTrajectoryService.d.ts.map +0 -1
- package/dist/src/services/SonaTrajectoryService.js +0 -539
- package/dist/src/services/SonaTrajectoryService.js.map +0 -1
- package/dist/src/utils/LegacyAttentionAdapter.d.ts +0 -93
- package/dist/src/utils/LegacyAttentionAdapter.d.ts.map +0 -1
- package/dist/src/utils/LegacyAttentionAdapter.js +0 -241
- package/dist/src/utils/LegacyAttentionAdapter.js.map +0 -1
- package/dist/src/utils/vector-math.d.ts +0 -29
- package/dist/src/utils/vector-math.d.ts.map +0 -1
- package/dist/src/utils/vector-math.js +0 -66
- package/dist/src/utils/vector-math.js.map +0 -1
|
@@ -1,639 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GNNService - Graph Neural Network Integration
|
|
3
|
-
*
|
|
4
|
-
* Provides high-level GNN capabilities on top of @ruvector/gnn:
|
|
5
|
-
* - Semantic intent classification
|
|
6
|
-
* - Graph-based skill recommendations
|
|
7
|
-
* - Code pattern similarity via graph embeddings
|
|
8
|
-
*
|
|
9
|
-
* Tries native @ruvector/gnn first (NAPI-RS), falls back to JS.
|
|
10
|
-
* All public methods are safe to call regardless of engine availability.
|
|
11
|
-
*
|
|
12
|
-
* Performance targets (ADR-062):
|
|
13
|
-
* - 100x-50000x speedup when native @ruvector/gnn is available
|
|
14
|
-
* - Zero-overhead JS fallback when native is not present
|
|
15
|
-
*/
|
|
16
|
-
export class GNNService {
|
|
17
|
-
gnn = null;
|
|
18
|
-
engineType = 'js';
|
|
19
|
-
initialized = false;
|
|
20
|
-
config;
|
|
21
|
-
constructor(config) {
|
|
22
|
-
// Default to 8 heads (128 % 8 = 0, valid for MultiHeadAttention)
|
|
23
|
-
const heads = config?.heads ?? config?.layers ?? 8;
|
|
24
|
-
this.config = {
|
|
25
|
-
inputDim: config?.inputDim ?? 384,
|
|
26
|
-
hiddenDim: config?.hiddenDim ?? 128,
|
|
27
|
-
outputDim: config?.outputDim ?? 64,
|
|
28
|
-
heads,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Initialize the GNN engine.
|
|
33
|
-
*
|
|
34
|
-
* Attempts to load @ruvector/gnn and create a GNN layer.
|
|
35
|
-
* Falls back to JS-based heuristics if unavailable.
|
|
36
|
-
*/
|
|
37
|
-
async initialize() {
|
|
38
|
-
if (this.initialized)
|
|
39
|
-
return;
|
|
40
|
-
try {
|
|
41
|
-
const mod = await import('@ruvector/gnn');
|
|
42
|
-
const RuvectorLayer = mod.RuvectorLayer ||
|
|
43
|
-
mod.default?.RuvectorLayer ||
|
|
44
|
-
mod.GNN ||
|
|
45
|
-
mod.default?.GNN;
|
|
46
|
-
if (RuvectorLayer) {
|
|
47
|
-
// @ruvector/gnn@0.1.25+ uses Result-based constructors
|
|
48
|
-
// RuvectorLayer(inputDim, hiddenDim, numHeads, dropout)
|
|
49
|
-
// numHeads must divide hiddenDim evenly (e.g., 128 % 8 = 0)
|
|
50
|
-
// Validate head count before calling native constructor
|
|
51
|
-
if (this.config.hiddenDim % this.config.heads !== 0) {
|
|
52
|
-
const validHeads = [];
|
|
53
|
-
for (let h = 1; h <= this.config.hiddenDim; h *= 2) {
|
|
54
|
-
if (this.config.hiddenDim % h === 0)
|
|
55
|
-
validHeads.push(h);
|
|
56
|
-
}
|
|
57
|
-
throw new Error(`Invalid head count: ${this.config.heads}. ` +
|
|
58
|
-
`hiddenDim (${this.config.hiddenDim}) must be divisible by heads. ` +
|
|
59
|
-
`Valid options: [${validHeads.join(', ')}]`);
|
|
60
|
-
}
|
|
61
|
-
try {
|
|
62
|
-
this.gnn = new RuvectorLayer(this.config.inputDim, this.config.hiddenDim, this.config.heads, // FIXED: Use heads parameter (not layers)
|
|
63
|
-
0.1 // dropout
|
|
64
|
-
);
|
|
65
|
-
this.engineType = 'native';
|
|
66
|
-
this.initialized = true;
|
|
67
|
-
console.log(`[GNNService] Using native @ruvector/gnn (v0.1.25+) with ${this.config.heads} heads`);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
catch (constructorError) {
|
|
71
|
-
// @ruvector/gnn@0.1.25+ throws errors instead of panicking
|
|
72
|
-
const errMsg = constructorError instanceof Error
|
|
73
|
-
? constructorError.message
|
|
74
|
-
: String(constructorError);
|
|
75
|
-
console.warn(`[GNNService] Native GNN constructor failed: ${errMsg}`);
|
|
76
|
-
console.warn('[GNNService] Falling back to JS implementation');
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
catch (e) {
|
|
81
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
82
|
-
console.warn(`[GNNService] Native GNN not available: ${msg}`);
|
|
83
|
-
}
|
|
84
|
-
this.engineType = 'js';
|
|
85
|
-
this.initialized = true;
|
|
86
|
-
console.log('[GNNService] Using JS fallback');
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Semantic intent classification.
|
|
90
|
-
*
|
|
91
|
-
* When native GNN is available, runs a forward pass on the embedding
|
|
92
|
-
* and maps logits to intent categories. Otherwise uses keyword matching.
|
|
93
|
-
*/
|
|
94
|
-
async classifyIntent(query, embedding) {
|
|
95
|
-
if (!this.initialized)
|
|
96
|
-
await this.initialize();
|
|
97
|
-
const intents = ['search', 'create', 'update', 'delete', 'analyze'];
|
|
98
|
-
if (this.engineType === 'native' && this.gnn) {
|
|
99
|
-
try {
|
|
100
|
-
const logits = typeof this.gnn.forward === 'function'
|
|
101
|
-
? this.gnn.forward(embedding, [], [])
|
|
102
|
-
: null;
|
|
103
|
-
if (logits && logits.length >= intents.length) {
|
|
104
|
-
const logitArray = logits instanceof Float32Array
|
|
105
|
-
? Array.from(logits)
|
|
106
|
-
: logits;
|
|
107
|
-
// Softmax over intent logits
|
|
108
|
-
const expLogits = logitArray.slice(0, intents.length).map((l) => Math.exp(l));
|
|
109
|
-
const expSum = expLogits.reduce((s, v) => s + v, 1e-10);
|
|
110
|
-
const probs = expLogits.map((e) => e / expSum);
|
|
111
|
-
let maxIdx = 0;
|
|
112
|
-
for (let i = 1; i < probs.length; i++) {
|
|
113
|
-
if (probs[i] > probs[maxIdx])
|
|
114
|
-
maxIdx = i;
|
|
115
|
-
}
|
|
116
|
-
return {
|
|
117
|
-
intent: intents[maxIdx],
|
|
118
|
-
confidence: probs[maxIdx],
|
|
119
|
-
logits: logitArray,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
// Fall through to JS
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
// JS fallback: keyword matching
|
|
128
|
-
const queryLower = query.toLowerCase();
|
|
129
|
-
if (queryLower.includes('search') || queryLower.includes('find') || queryLower.includes('lookup')) {
|
|
130
|
-
return { intent: 'search', confidence: 0.8 };
|
|
131
|
-
}
|
|
132
|
-
if (queryLower.includes('create') || queryLower.includes('add') || queryLower.includes('new')) {
|
|
133
|
-
return { intent: 'create', confidence: 0.8 };
|
|
134
|
-
}
|
|
135
|
-
if (queryLower.includes('update') || queryLower.includes('edit') || queryLower.includes('modify')) {
|
|
136
|
-
return { intent: 'update', confidence: 0.8 };
|
|
137
|
-
}
|
|
138
|
-
if (queryLower.includes('delete') || queryLower.includes('remove') || queryLower.includes('drop')) {
|
|
139
|
-
return { intent: 'delete', confidence: 0.8 };
|
|
140
|
-
}
|
|
141
|
-
if (queryLower.includes('analyze') || queryLower.includes('report') || queryLower.includes('summary')) {
|
|
142
|
-
return { intent: 'analyze', confidence: 0.8 };
|
|
143
|
-
}
|
|
144
|
-
return { intent: 'search', confidence: 0.5 };
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Graph-based skill recommendations.
|
|
148
|
-
*
|
|
149
|
-
* Uses GNN node classification when available, otherwise
|
|
150
|
-
* returns adjacent skills from the skill graph map.
|
|
151
|
-
*/
|
|
152
|
-
async recommendSkills(currentSkill, skillGraph) {
|
|
153
|
-
if (!this.initialized)
|
|
154
|
-
await this.initialize();
|
|
155
|
-
if (this.engineType === 'native' && this.gnn) {
|
|
156
|
-
try {
|
|
157
|
-
// Build adjacency from skill graph for GNN
|
|
158
|
-
const skills = Object.keys(skillGraph);
|
|
159
|
-
const idx = skills.indexOf(currentSkill);
|
|
160
|
-
if (idx >= 0 && typeof this.gnn.forward === 'function') {
|
|
161
|
-
// Create a simple embedding from the skill index
|
|
162
|
-
const skillEmbed = new Float32Array(this.config.inputDim);
|
|
163
|
-
skillEmbed[idx % this.config.inputDim] = 1.0;
|
|
164
|
-
const neighborEmbeds = [];
|
|
165
|
-
const weights = [];
|
|
166
|
-
const neighbors = skillGraph[currentSkill] || [];
|
|
167
|
-
for (const neighbor of neighbors) {
|
|
168
|
-
const nIdx = skills.indexOf(neighbor);
|
|
169
|
-
if (nIdx >= 0) {
|
|
170
|
-
const nEmbed = new Float32Array(this.config.inputDim);
|
|
171
|
-
nEmbed[nIdx % this.config.inputDim] = 1.0;
|
|
172
|
-
neighborEmbeds.push(nEmbed);
|
|
173
|
-
weights.push(1.0);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
if (neighborEmbeds.length > 0) {
|
|
177
|
-
const enhanced = this.gnn.forward(skillEmbed, neighborEmbeds, weights);
|
|
178
|
-
if (enhanced) {
|
|
179
|
-
// Use enhanced embedding to rank skills by similarity
|
|
180
|
-
const ranked = skills
|
|
181
|
-
.filter(s => s !== currentSkill)
|
|
182
|
-
.map(s => {
|
|
183
|
-
const sIdx = skills.indexOf(s);
|
|
184
|
-
return { skill: s, score: enhanced[sIdx % enhanced.length] || 0 };
|
|
185
|
-
})
|
|
186
|
-
.sort((a, b) => b.score - a.score);
|
|
187
|
-
return ranked.slice(0, 5).map(r => r.skill);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
catch {
|
|
193
|
-
// Fall through to JS
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
// JS fallback: return direct neighbors from graph
|
|
197
|
-
const neighbors = skillGraph[currentSkill] || [];
|
|
198
|
-
if (neighbors.length > 0) {
|
|
199
|
-
return neighbors.slice(0, 5);
|
|
200
|
-
}
|
|
201
|
-
return Object.keys(skillGraph).filter(s => s !== currentSkill).slice(0, 5);
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Find similar code patterns using graph embedding similarity.
|
|
205
|
-
*
|
|
206
|
-
* When native GNN is available, uses graph-level similarity.
|
|
207
|
-
* Otherwise falls back to cosine similarity.
|
|
208
|
-
*/
|
|
209
|
-
async findSimilarPatterns(pattern, patterns) {
|
|
210
|
-
if (!this.initialized)
|
|
211
|
-
await this.initialize();
|
|
212
|
-
if (this.engineType === 'native' && this.gnn) {
|
|
213
|
-
try {
|
|
214
|
-
const query = pattern instanceof Float32Array
|
|
215
|
-
? pattern
|
|
216
|
-
: new Float32Array(pattern);
|
|
217
|
-
const candidates = patterns.map(p => p instanceof Float32Array ? p : new Float32Array(p));
|
|
218
|
-
// Use differentiable search if available
|
|
219
|
-
if (typeof this.gnn.forward === 'function') {
|
|
220
|
-
const enhanced = this.gnn.forward(query, candidates, candidates.map(() => 1.0));
|
|
221
|
-
if (enhanced) {
|
|
222
|
-
return patterns.map((_, i) => ({
|
|
223
|
-
index: i,
|
|
224
|
-
similarity: this.cosineSim(Array.from(enhanced), patterns[i]),
|
|
225
|
-
})).sort((a, b) => b.similarity - a.similarity);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
catch {
|
|
230
|
-
// Fall through to JS
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
// JS fallback: cosine similarity
|
|
234
|
-
return patterns.map((p, i) => ({
|
|
235
|
-
index: i,
|
|
236
|
-
similarity: this.cosineSim(pattern, p),
|
|
237
|
-
})).sort((a, b) => b.similarity - a.similarity);
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Get the current engine type.
|
|
241
|
-
*/
|
|
242
|
-
getEngineType() {
|
|
243
|
-
return this.engineType;
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Check if the service is initialized.
|
|
247
|
-
*/
|
|
248
|
-
isInitialized() {
|
|
249
|
-
return this.initialized;
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Get service statistics.
|
|
253
|
-
*/
|
|
254
|
-
getStats() {
|
|
255
|
-
return {
|
|
256
|
-
engineType: this.engineType,
|
|
257
|
-
initialized: this.initialized,
|
|
258
|
-
config: this.config,
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Graph Convolutional Network (GCN) for skill matching.
|
|
263
|
-
*
|
|
264
|
-
* Uses GCN layers to learn representations of skills based on their
|
|
265
|
-
* relationships in the skill graph. Achieves >90% accuracy when native.
|
|
266
|
-
*/
|
|
267
|
-
async matchSkillsGCN(taskEmbedding, skillGraph, topK = 5) {
|
|
268
|
-
if (!this.initialized)
|
|
269
|
-
await this.initialize();
|
|
270
|
-
if (this.engineType === 'native' && this.gnn) {
|
|
271
|
-
try {
|
|
272
|
-
const skills = Object.keys(skillGraph);
|
|
273
|
-
const results = [];
|
|
274
|
-
for (const skill of skills) {
|
|
275
|
-
const skillData = skillGraph[skill];
|
|
276
|
-
const neighborEmbeddings = [];
|
|
277
|
-
const weights = [];
|
|
278
|
-
// Collect neighbor embeddings for GCN aggregation
|
|
279
|
-
for (const neighbor of skillData.neighbors) {
|
|
280
|
-
if (skillGraph[neighbor]) {
|
|
281
|
-
neighborEmbeddings.push(skillGraph[neighbor].embedding);
|
|
282
|
-
weights.push(1.0 / skillData.neighbors.length); // Normalized weights
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
// Forward pass through GCN
|
|
286
|
-
if (typeof this.gnn.forward === 'function') {
|
|
287
|
-
const enhanced = this.gnn.forward(skillData.embedding, neighborEmbeddings, weights);
|
|
288
|
-
if (enhanced) {
|
|
289
|
-
const similarity = this.cosineSim(taskEmbedding, enhanced);
|
|
290
|
-
results.push({
|
|
291
|
-
skill,
|
|
292
|
-
score: similarity,
|
|
293
|
-
confidence: similarity > 0.8 ? 0.95 : similarity > 0.6 ? 0.85 : 0.75,
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
return results
|
|
299
|
-
.sort((a, b) => b.score - a.score)
|
|
300
|
-
.slice(0, topK);
|
|
301
|
-
}
|
|
302
|
-
catch (e) {
|
|
303
|
-
console.warn('[GNNService] GCN skill matching failed, falling back:', e);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
// JS fallback: simple cosine similarity without graph convolution
|
|
307
|
-
const skills = Object.keys(skillGraph);
|
|
308
|
-
return skills
|
|
309
|
-
.map(skill => ({
|
|
310
|
-
skill,
|
|
311
|
-
score: this.cosineSim(taskEmbedding, skillGraph[skill].embedding),
|
|
312
|
-
confidence: 0.6,
|
|
313
|
-
}))
|
|
314
|
-
.sort((a, b) => b.score - a.score)
|
|
315
|
-
.slice(0, topK);
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* Graph Attention Network (GAT) for context understanding.
|
|
319
|
-
*
|
|
320
|
-
* Applies attention mechanisms to weight the importance of different
|
|
321
|
-
* context nodes when making predictions.
|
|
322
|
-
*/
|
|
323
|
-
async understandContextGAT(queryEmbedding, contextNodes, attentionHeads = 4) {
|
|
324
|
-
if (!this.initialized)
|
|
325
|
-
await this.initialize();
|
|
326
|
-
if (this.engineType === 'native' && this.gnn) {
|
|
327
|
-
try {
|
|
328
|
-
const embeddings = contextNodes.map(n => n.embedding);
|
|
329
|
-
const weights = new Array(contextNodes.length).fill(1.0);
|
|
330
|
-
// Multi-head attention via forward pass
|
|
331
|
-
if (typeof this.gnn.forward === 'function') {
|
|
332
|
-
const attended = this.gnn.forward(queryEmbedding, embeddings, weights);
|
|
333
|
-
if (attended) {
|
|
334
|
-
// Calculate attention weights based on similarity
|
|
335
|
-
const attentionWeights = {};
|
|
336
|
-
let maxWeight = 0;
|
|
337
|
-
for (let i = 0; i < contextNodes.length; i++) {
|
|
338
|
-
const weight = this.cosineSim(attended, contextNodes[i].embedding);
|
|
339
|
-
attentionWeights[contextNodes[i].id] = weight;
|
|
340
|
-
maxWeight = Math.max(maxWeight, weight);
|
|
341
|
-
}
|
|
342
|
-
// Normalize weights
|
|
343
|
-
for (const key in attentionWeights) {
|
|
344
|
-
attentionWeights[key] /= maxWeight || 1.0;
|
|
345
|
-
}
|
|
346
|
-
// Find dominant types
|
|
347
|
-
const typeWeights = {};
|
|
348
|
-
for (const node of contextNodes) {
|
|
349
|
-
typeWeights[node.type] = (typeWeights[node.type] || 0) + attentionWeights[node.id];
|
|
350
|
-
}
|
|
351
|
-
const dominantTypes = Object.entries(typeWeights)
|
|
352
|
-
.sort(([, a], [, b]) => b - a)
|
|
353
|
-
.slice(0, 3)
|
|
354
|
-
.map(([type]) => type);
|
|
355
|
-
return {
|
|
356
|
-
contextVector: attended,
|
|
357
|
-
attentionWeights,
|
|
358
|
-
dominantTypes,
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
catch (e) {
|
|
364
|
-
console.warn('[GNNService] GAT context understanding failed, falling back:', e);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
// JS fallback: uniform attention
|
|
368
|
-
const avgEmbedding = new Float32Array(queryEmbedding.length);
|
|
369
|
-
for (const node of contextNodes) {
|
|
370
|
-
for (let i = 0; i < avgEmbedding.length; i++) {
|
|
371
|
-
avgEmbedding[i] += node.embedding[i] / contextNodes.length;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
const attentionWeights = {};
|
|
375
|
-
contextNodes.forEach(n => {
|
|
376
|
-
attentionWeights[n.id] = 1.0 / contextNodes.length;
|
|
377
|
-
});
|
|
378
|
-
const typeWeights = {};
|
|
379
|
-
for (const node of contextNodes) {
|
|
380
|
-
typeWeights[node.type] = (typeWeights[node.type] || 0) + 1;
|
|
381
|
-
}
|
|
382
|
-
const dominantTypes = Object.entries(typeWeights)
|
|
383
|
-
.sort(([, a], [, b]) => b - a)
|
|
384
|
-
.map(([type]) => type);
|
|
385
|
-
return {
|
|
386
|
-
contextVector: avgEmbedding,
|
|
387
|
-
attentionWeights,
|
|
388
|
-
dominantTypes,
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Process heterogeneous graphs with multiple node and edge types.
|
|
393
|
-
*
|
|
394
|
-
* Handles graphs with different types of entities (agents, tasks, skills)
|
|
395
|
-
* and relationships (depends_on, requires, similar_to).
|
|
396
|
-
*/
|
|
397
|
-
async processHeterogeneousGraph(graph, queryNodeId) {
|
|
398
|
-
if (!this.initialized)
|
|
399
|
-
await this.initialize();
|
|
400
|
-
const nodeMap = new Map(graph.nodes.map(n => [n.id, n]));
|
|
401
|
-
const queryNode = nodeMap.get(queryNodeId);
|
|
402
|
-
if (!queryNode) {
|
|
403
|
-
throw new Error(`Query node ${queryNodeId} not found in graph`);
|
|
404
|
-
}
|
|
405
|
-
if (this.engineType === 'native' && this.gnn) {
|
|
406
|
-
try {
|
|
407
|
-
// Build adjacency for heterogeneous GNN
|
|
408
|
-
const neighbors = graph.edges
|
|
409
|
-
.filter(e => e.from === queryNodeId)
|
|
410
|
-
.map(e => {
|
|
411
|
-
const neighbor = nodeMap.get(e.to);
|
|
412
|
-
return neighbor ? { ...neighbor, edgeType: e.type, weight: e.weight } : null;
|
|
413
|
-
})
|
|
414
|
-
.filter(n => n !== null);
|
|
415
|
-
if (neighbors.length > 0 && typeof this.gnn.forward === 'function') {
|
|
416
|
-
const enhanced = this.gnn.forward(queryNode.embedding, neighbors.map(n => n.embedding), neighbors.map(n => n.weight));
|
|
417
|
-
if (enhanced) {
|
|
418
|
-
// Calculate relevance for all nodes
|
|
419
|
-
const relatedNodes = graph.nodes
|
|
420
|
-
.filter(n => n.id !== queryNodeId)
|
|
421
|
-
.map(n => ({
|
|
422
|
-
id: n.id,
|
|
423
|
-
type: n.type,
|
|
424
|
-
relevance: this.cosineSim(enhanced, n.embedding),
|
|
425
|
-
}))
|
|
426
|
-
.sort((a, b) => b.relevance - a.relevance)
|
|
427
|
-
.slice(0, 10);
|
|
428
|
-
// Find strongest pathways
|
|
429
|
-
const pathways = this.findStrongPathways(graph, queryNodeId, relatedNodes.slice(0, 5));
|
|
430
|
-
return {
|
|
431
|
-
embedding: enhanced,
|
|
432
|
-
relatedNodes,
|
|
433
|
-
pathways,
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
catch (e) {
|
|
439
|
-
console.warn('[GNNService] Heterogeneous graph processing failed, falling back:', e);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
// JS fallback: direct neighbor aggregation
|
|
443
|
-
const neighbors = graph.edges
|
|
444
|
-
.filter(e => e.from === queryNodeId)
|
|
445
|
-
.map(e => nodeMap.get(e.to))
|
|
446
|
-
.filter(n => n !== undefined);
|
|
447
|
-
const avgEmbedding = new Float32Array(queryNode.embedding.length);
|
|
448
|
-
for (let i = 0; i < avgEmbedding.length; i++) {
|
|
449
|
-
avgEmbedding[i] = queryNode.embedding[i];
|
|
450
|
-
for (const neighbor of neighbors) {
|
|
451
|
-
avgEmbedding[i] += neighbor.embedding[i] / (neighbors.length + 1);
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
const relatedNodes = graph.nodes
|
|
455
|
-
.filter(n => n.id !== queryNodeId)
|
|
456
|
-
.map(n => ({
|
|
457
|
-
id: n.id,
|
|
458
|
-
type: n.type,
|
|
459
|
-
relevance: this.cosineSim(avgEmbedding, n.embedding),
|
|
460
|
-
}))
|
|
461
|
-
.sort((a, b) => b.relevance - a.relevance)
|
|
462
|
-
.slice(0, 10);
|
|
463
|
-
const pathways = this.findStrongPathways(graph, queryNodeId, relatedNodes.slice(0, 5));
|
|
464
|
-
return {
|
|
465
|
-
embedding: avgEmbedding,
|
|
466
|
-
relatedNodes,
|
|
467
|
-
pathways,
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* Node classification for task categorization.
|
|
472
|
-
*
|
|
473
|
-
* Classifies nodes into predefined categories using GNN-based features.
|
|
474
|
-
*/
|
|
475
|
-
async classifyNode(nodeEmbedding, neighborEmbeddings, categories) {
|
|
476
|
-
if (!this.initialized)
|
|
477
|
-
await this.initialize();
|
|
478
|
-
if (this.engineType === 'native' && this.gnn && typeof this.gnn.forward === 'function') {
|
|
479
|
-
try {
|
|
480
|
-
const enhanced = this.gnn.forward(nodeEmbedding, neighborEmbeddings, neighborEmbeddings.map(() => 1.0));
|
|
481
|
-
if (enhanced && enhanced.length >= categories.length) {
|
|
482
|
-
// Use first N dimensions as category logits
|
|
483
|
-
const logits = Array.from(enhanced.slice(0, categories.length));
|
|
484
|
-
const expLogits = logits.map((l) => Math.exp(l));
|
|
485
|
-
const expSum = expLogits.reduce((s, v) => s + v, 1e-10);
|
|
486
|
-
const probs = expLogits.map(e => e / expSum);
|
|
487
|
-
let maxIdx = 0;
|
|
488
|
-
for (let i = 1; i < probs.length; i++) {
|
|
489
|
-
if (probs[i] > probs[maxIdx])
|
|
490
|
-
maxIdx = i;
|
|
491
|
-
}
|
|
492
|
-
const scores = {};
|
|
493
|
-
categories.forEach((cat, i) => {
|
|
494
|
-
scores[cat] = probs[i];
|
|
495
|
-
});
|
|
496
|
-
return {
|
|
497
|
-
category: categories[maxIdx],
|
|
498
|
-
confidence: probs[maxIdx],
|
|
499
|
-
scores,
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
catch (e) {
|
|
504
|
-
console.warn('[GNNService] Node classification failed, falling back:', e);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
// JS fallback: random with slight bias
|
|
508
|
-
const scores = {};
|
|
509
|
-
const probs = categories.map(() => Math.random());
|
|
510
|
-
const sum = probs.reduce((s, v) => s + v, 0);
|
|
511
|
-
const normalized = probs.map(p => p / sum);
|
|
512
|
-
let maxIdx = 0;
|
|
513
|
-
categories.forEach((cat, i) => {
|
|
514
|
-
scores[cat] = normalized[i];
|
|
515
|
-
if (normalized[i] > normalized[maxIdx])
|
|
516
|
-
maxIdx = i;
|
|
517
|
-
});
|
|
518
|
-
return {
|
|
519
|
-
category: categories[maxIdx],
|
|
520
|
-
confidence: normalized[maxIdx],
|
|
521
|
-
scores,
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
/**
|
|
525
|
-
* Link prediction for workflow optimization.
|
|
526
|
-
*
|
|
527
|
-
* Predicts likely connections between nodes to suggest workflow improvements.
|
|
528
|
-
*/
|
|
529
|
-
async predictLinks(sourceNode, candidateNodes, existingEdges, topK = 5) {
|
|
530
|
-
if (!this.initialized)
|
|
531
|
-
await this.initialize();
|
|
532
|
-
if (this.engineType === 'native' && this.gnn && typeof this.gnn.forward === 'function') {
|
|
533
|
-
try {
|
|
534
|
-
const enhanced = this.gnn.forward(sourceNode.embedding, candidateNodes.map(n => n.embedding), candidateNodes.map(() => 1.0));
|
|
535
|
-
if (enhanced) {
|
|
536
|
-
const predictions = candidateNodes.map(node => {
|
|
537
|
-
// Check if edge already exists
|
|
538
|
-
const exists = existingEdges.some(e => e.from === sourceNode.id && e.to === node.id);
|
|
539
|
-
if (exists) {
|
|
540
|
-
return { targetId: node.id, probability: 0, reasoning: 'Edge already exists' };
|
|
541
|
-
}
|
|
542
|
-
const similarity = this.cosineSim(enhanced, node.embedding);
|
|
543
|
-
const probability = 1 / (1 + Math.exp(-5 * (similarity - 0.5))); // Sigmoid scaling
|
|
544
|
-
let reasoning = 'Strong structural similarity';
|
|
545
|
-
if (probability > 0.8)
|
|
546
|
-
reasoning = 'Very high compatibility detected';
|
|
547
|
-
else if (probability > 0.6)
|
|
548
|
-
reasoning = 'Good potential for connection';
|
|
549
|
-
else if (probability > 0.4)
|
|
550
|
-
reasoning = 'Moderate connection potential';
|
|
551
|
-
else
|
|
552
|
-
reasoning = 'Weak connection likelihood';
|
|
553
|
-
return { targetId: node.id, probability, reasoning };
|
|
554
|
-
});
|
|
555
|
-
return predictions
|
|
556
|
-
.filter(p => p.probability > 0)
|
|
557
|
-
.sort((a, b) => b.probability - a.probability)
|
|
558
|
-
.slice(0, topK);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
catch (e) {
|
|
562
|
-
console.warn('[GNNService] Link prediction failed, falling back:', e);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
// JS fallback: cosine similarity based
|
|
566
|
-
return candidateNodes
|
|
567
|
-
.map(node => {
|
|
568
|
-
const exists = existingEdges.some(e => e.from === sourceNode.id && e.to === node.id);
|
|
569
|
-
if (exists) {
|
|
570
|
-
return { targetId: node.id, probability: 0, reasoning: 'Edge already exists' };
|
|
571
|
-
}
|
|
572
|
-
const similarity = this.cosineSim(sourceNode.embedding, node.embedding);
|
|
573
|
-
return {
|
|
574
|
-
targetId: node.id,
|
|
575
|
-
probability: similarity,
|
|
576
|
-
reasoning: similarity > 0.7 ? 'High similarity' : 'Moderate similarity',
|
|
577
|
-
};
|
|
578
|
-
})
|
|
579
|
-
.filter(p => p.probability > 0)
|
|
580
|
-
.sort((a, b) => b.probability - a.probability)
|
|
581
|
-
.slice(0, topK);
|
|
582
|
-
}
|
|
583
|
-
// ---------------------------------------------------------------------------
|
|
584
|
-
// Private
|
|
585
|
-
// ---------------------------------------------------------------------------
|
|
586
|
-
findStrongPathways(graph, startNodeId, targetNodes) {
|
|
587
|
-
const pathways = [];
|
|
588
|
-
for (const target of targetNodes) {
|
|
589
|
-
// Simple BFS to find shortest path
|
|
590
|
-
const visited = new Set();
|
|
591
|
-
const queue = [
|
|
592
|
-
{ nodeId: startNodeId, path: [startNodeId] },
|
|
593
|
-
];
|
|
594
|
-
while (queue.length > 0) {
|
|
595
|
-
const current = queue.shift();
|
|
596
|
-
if (current.nodeId === target.id) {
|
|
597
|
-
// Calculate pathway strength
|
|
598
|
-
let strength = target.relevance;
|
|
599
|
-
for (let i = 0; i < current.path.length - 1; i++) {
|
|
600
|
-
const edge = graph.edges.find(e => e.from === current.path[i] && e.to === current.path[i + 1]);
|
|
601
|
-
strength *= edge?.weight || 0.5;
|
|
602
|
-
}
|
|
603
|
-
pathways.push({ path: current.path, strength });
|
|
604
|
-
break;
|
|
605
|
-
}
|
|
606
|
-
if (visited.has(current.nodeId) || current.path.length > 4) {
|
|
607
|
-
continue;
|
|
608
|
-
}
|
|
609
|
-
visited.add(current.nodeId);
|
|
610
|
-
const neighbors = graph.edges
|
|
611
|
-
.filter(e => e.from === current.nodeId)
|
|
612
|
-
.map(e => e.to);
|
|
613
|
-
for (const neighbor of neighbors) {
|
|
614
|
-
if (!visited.has(neighbor)) {
|
|
615
|
-
queue.push({
|
|
616
|
-
nodeId: neighbor,
|
|
617
|
-
path: [...current.path, neighbor],
|
|
618
|
-
});
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
return pathways.sort((a, b) => b.strength - a.strength).slice(0, 5);
|
|
624
|
-
}
|
|
625
|
-
cosineSim(a, b) {
|
|
626
|
-
let dot = 0;
|
|
627
|
-
let normA = 0;
|
|
628
|
-
let normB = 0;
|
|
629
|
-
const len = Math.min(a.length, b.length);
|
|
630
|
-
for (let i = 0; i < len; i++) {
|
|
631
|
-
dot += a[i] * b[i];
|
|
632
|
-
normA += a[i] * a[i];
|
|
633
|
-
normB += b[i] * b[i];
|
|
634
|
-
}
|
|
635
|
-
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
636
|
-
return denom > 0 ? dot / denom : 0;
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
//# sourceMappingURL=GNNService.js.map
|