@cogitator-ai/memory 0.1.0 → 0.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.
Files changed (53) hide show
  1. package/README.md +572 -21
  2. package/dist/__tests__/context-builder.test.js +2 -2
  3. package/dist/__tests__/context-builder.test.js.map +1 -1
  4. package/dist/__tests__/memory-adapter.test.js +1 -1
  5. package/dist/__tests__/memory-adapter.test.js.map +1 -1
  6. package/dist/__tests__/token-counter.test.js +1 -1
  7. package/dist/__tests__/token-counter.test.js.map +1 -1
  8. package/dist/adapters/base.d.ts.map +1 -1
  9. package/dist/adapters/base.js.map +1 -1
  10. package/dist/adapters/memory.d.ts.map +1 -1
  11. package/dist/adapters/memory.js.map +1 -1
  12. package/dist/adapters/postgres.d.ts.map +1 -1
  13. package/dist/adapters/postgres.js +11 -15
  14. package/dist/adapters/postgres.js.map +1 -1
  15. package/dist/adapters/redis.d.ts.map +1 -1
  16. package/dist/adapters/redis.js.map +1 -1
  17. package/dist/context-builder.d.ts.map +1 -1
  18. package/dist/context-builder.js +7 -15
  19. package/dist/context-builder.js.map +1 -1
  20. package/dist/embedding/factory.d.ts.map +1 -1
  21. package/dist/embedding/factory.js.map +1 -1
  22. package/dist/embedding/openai.d.ts.map +1 -1
  23. package/dist/embedding/openai.js +1 -3
  24. package/dist/embedding/openai.js.map +1 -1
  25. package/dist/index.d.ts +4 -2
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +2 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/knowledge-graph/entity-extractor.d.ts +30 -0
  30. package/dist/knowledge-graph/entity-extractor.d.ts.map +1 -0
  31. package/dist/knowledge-graph/entity-extractor.js +158 -0
  32. package/dist/knowledge-graph/entity-extractor.js.map +1 -0
  33. package/dist/knowledge-graph/graph-adapter.d.ts +56 -0
  34. package/dist/knowledge-graph/graph-adapter.d.ts.map +1 -0
  35. package/dist/knowledge-graph/graph-adapter.js +652 -0
  36. package/dist/knowledge-graph/graph-adapter.js.map +1 -0
  37. package/dist/knowledge-graph/graph-context-builder.d.ts +23 -0
  38. package/dist/knowledge-graph/graph-context-builder.d.ts.map +1 -0
  39. package/dist/knowledge-graph/graph-context-builder.js +202 -0
  40. package/dist/knowledge-graph/graph-context-builder.js.map +1 -0
  41. package/dist/knowledge-graph/index.d.ts +9 -0
  42. package/dist/knowledge-graph/index.d.ts.map +1 -0
  43. package/dist/knowledge-graph/index.js +6 -0
  44. package/dist/knowledge-graph/index.js.map +1 -0
  45. package/dist/knowledge-graph/inference-engine.d.ts +17 -0
  46. package/dist/knowledge-graph/inference-engine.d.ts.map +1 -0
  47. package/dist/knowledge-graph/inference-engine.js +270 -0
  48. package/dist/knowledge-graph/inference-engine.js.map +1 -0
  49. package/dist/knowledge-graph/schema.d.ts +854 -0
  50. package/dist/knowledge-graph/schema.d.ts.map +1 -0
  51. package/dist/knowledge-graph/schema.js +166 -0
  52. package/dist/knowledge-graph/schema.js.map +1 -0
  53. package/package.json +6 -5
@@ -0,0 +1,652 @@
1
+ import { nanoid } from 'nanoid';
2
+ export class PostgresGraphAdapter {
3
+ pool;
4
+ schema;
5
+ vectorDimensions;
6
+ initialized = false;
7
+ constructor(config) {
8
+ this.pool = config.pool;
9
+ this.schema = config.schema ?? 'cogitator';
10
+ this.vectorDimensions = config.vectorDimensions ?? 1536;
11
+ }
12
+ async initialize() {
13
+ if (this.initialized)
14
+ return;
15
+ await this.pool.query(`
16
+ CREATE TABLE IF NOT EXISTS ${this.schema}.graph_nodes (
17
+ id TEXT PRIMARY KEY,
18
+ agent_id TEXT NOT NULL,
19
+ type TEXT NOT NULL,
20
+ name TEXT NOT NULL,
21
+ aliases TEXT[] DEFAULT '{}',
22
+ description TEXT,
23
+ properties JSONB DEFAULT '{}',
24
+ embedding vector(${this.vectorDimensions}),
25
+ confidence REAL NOT NULL DEFAULT 1.0,
26
+ source TEXT NOT NULL,
27
+ created_at TIMESTAMPTZ DEFAULT NOW(),
28
+ updated_at TIMESTAMPTZ DEFAULT NOW(),
29
+ last_accessed_at TIMESTAMPTZ DEFAULT NOW(),
30
+ access_count INTEGER DEFAULT 0,
31
+ metadata JSONB DEFAULT '{}'
32
+ )
33
+ `);
34
+ await this.pool.query(`
35
+ CREATE TABLE IF NOT EXISTS ${this.schema}.graph_edges (
36
+ id TEXT PRIMARY KEY,
37
+ agent_id TEXT NOT NULL,
38
+ source_node_id TEXT NOT NULL REFERENCES ${this.schema}.graph_nodes(id) ON DELETE CASCADE,
39
+ target_node_id TEXT NOT NULL REFERENCES ${this.schema}.graph_nodes(id) ON DELETE CASCADE,
40
+ type TEXT NOT NULL,
41
+ label TEXT,
42
+ weight REAL NOT NULL DEFAULT 1.0,
43
+ bidirectional BOOLEAN DEFAULT FALSE,
44
+ properties JSONB DEFAULT '{}',
45
+ confidence REAL NOT NULL DEFAULT 1.0,
46
+ source TEXT NOT NULL,
47
+ created_at TIMESTAMPTZ DEFAULT NOW(),
48
+ updated_at TIMESTAMPTZ DEFAULT NOW(),
49
+ valid_from TIMESTAMPTZ,
50
+ valid_until TIMESTAMPTZ,
51
+ metadata JSONB DEFAULT '{}'
52
+ )
53
+ `);
54
+ await this.pool.query(`
55
+ CREATE INDEX IF NOT EXISTS idx_graph_nodes_agent_id
56
+ ON ${this.schema}.graph_nodes(agent_id)
57
+ `);
58
+ await this.pool.query(`
59
+ CREATE INDEX IF NOT EXISTS idx_graph_nodes_type
60
+ ON ${this.schema}.graph_nodes(agent_id, type)
61
+ `);
62
+ await this.pool.query(`
63
+ CREATE INDEX IF NOT EXISTS idx_graph_nodes_name
64
+ ON ${this.schema}.graph_nodes(agent_id, name)
65
+ `);
66
+ await this.pool.query(`
67
+ CREATE INDEX IF NOT EXISTS idx_graph_edges_agent_id
68
+ ON ${this.schema}.graph_edges(agent_id)
69
+ `);
70
+ await this.pool.query(`
71
+ CREATE INDEX IF NOT EXISTS idx_graph_edges_source
72
+ ON ${this.schema}.graph_edges(source_node_id)
73
+ `);
74
+ await this.pool.query(`
75
+ CREATE INDEX IF NOT EXISTS idx_graph_edges_target
76
+ ON ${this.schema}.graph_edges(target_node_id)
77
+ `);
78
+ await this.pool.query(`
79
+ CREATE INDEX IF NOT EXISTS idx_graph_edges_type
80
+ ON ${this.schema}.graph_edges(agent_id, type)
81
+ `);
82
+ try {
83
+ await this.pool.query(`
84
+ CREATE INDEX IF NOT EXISTS idx_graph_nodes_embedding
85
+ ON ${this.schema}.graph_nodes
86
+ USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100)
87
+ `);
88
+ }
89
+ catch { }
90
+ this.initialized = true;
91
+ }
92
+ success(data) {
93
+ return { success: true, data };
94
+ }
95
+ failure(error) {
96
+ return { success: false, error };
97
+ }
98
+ generateId(prefix) {
99
+ return `${prefix}_${nanoid(12)}`;
100
+ }
101
+ async addNode(node) {
102
+ await this.initialize();
103
+ const id = this.generateId('node');
104
+ const now = new Date();
105
+ const embeddingStr = node.embedding ? `[${node.embedding.join(',')}]` : null;
106
+ await this.pool.query(`INSERT INTO ${this.schema}.graph_nodes
107
+ (id, agent_id, type, name, aliases, description, properties, embedding, confidence, source, metadata, created_at, updated_at, last_accessed_at, access_count)
108
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $12, $12, 0)`, [
109
+ id,
110
+ node.agentId,
111
+ node.type,
112
+ node.name,
113
+ node.aliases,
114
+ node.description ?? null,
115
+ node.properties,
116
+ embeddingStr,
117
+ node.confidence,
118
+ node.source,
119
+ node.metadata ?? {},
120
+ now,
121
+ ]);
122
+ return this.success({
123
+ ...node,
124
+ id,
125
+ createdAt: now,
126
+ updatedAt: now,
127
+ lastAccessedAt: now,
128
+ accessCount: 0,
129
+ });
130
+ }
131
+ async getNode(nodeId) {
132
+ await this.initialize();
133
+ await this.pool.query(`UPDATE ${this.schema}.graph_nodes
134
+ SET last_accessed_at = NOW(), access_count = access_count + 1
135
+ WHERE id = $1`, [nodeId]);
136
+ const result = await this.pool.query(`SELECT * FROM ${this.schema}.graph_nodes WHERE id = $1`, [nodeId]);
137
+ if (result.rows.length === 0)
138
+ return this.success(null);
139
+ return this.success(this.rowToNode(result.rows[0]));
140
+ }
141
+ async getNodeByName(agentId, name) {
142
+ await this.initialize();
143
+ const result = await this.pool.query(`SELECT * FROM ${this.schema}.graph_nodes
144
+ WHERE agent_id = $1 AND (name = $2 OR $2 = ANY(aliases))`, [agentId, name]);
145
+ if (result.rows.length === 0)
146
+ return this.success(null);
147
+ return this.success(this.rowToNode(result.rows[0]));
148
+ }
149
+ async updateNode(nodeId, updates) {
150
+ await this.initialize();
151
+ const setClauses = ['updated_at = NOW()'];
152
+ const params = [];
153
+ let paramIndex = 1;
154
+ if (updates.name !== undefined) {
155
+ setClauses.push(`name = $${paramIndex++}`);
156
+ params.push(updates.name);
157
+ }
158
+ if (updates.aliases !== undefined) {
159
+ setClauses.push(`aliases = $${paramIndex++}`);
160
+ params.push(updates.aliases);
161
+ }
162
+ if (updates.description !== undefined) {
163
+ setClauses.push(`description = $${paramIndex++}`);
164
+ params.push(updates.description);
165
+ }
166
+ if (updates.properties !== undefined) {
167
+ setClauses.push(`properties = $${paramIndex++}`);
168
+ params.push(updates.properties);
169
+ }
170
+ if (updates.confidence !== undefined) {
171
+ setClauses.push(`confidence = $${paramIndex++}`);
172
+ params.push(updates.confidence);
173
+ }
174
+ if (updates.metadata !== undefined) {
175
+ setClauses.push(`metadata = $${paramIndex++}`);
176
+ params.push(updates.metadata);
177
+ }
178
+ if (updates.embedding !== undefined) {
179
+ setClauses.push(`embedding = $${paramIndex++}`);
180
+ params.push(`[${updates.embedding.join(',')}]`);
181
+ }
182
+ params.push(nodeId);
183
+ const result = await this.pool.query(`UPDATE ${this.schema}.graph_nodes SET ${setClauses.join(', ')} WHERE id = $${paramIndex} RETURNING *`, params);
184
+ if (result.rows.length === 0) {
185
+ return this.failure(`Node not found: ${nodeId}`);
186
+ }
187
+ return this.success(this.rowToNode(result.rows[0]));
188
+ }
189
+ async deleteNode(nodeId) {
190
+ await this.initialize();
191
+ await this.pool.query(`DELETE FROM ${this.schema}.graph_nodes WHERE id = $1`, [nodeId]);
192
+ return this.success(undefined);
193
+ }
194
+ async queryNodes(query) {
195
+ await this.initialize();
196
+ let sql = `SELECT * FROM ${this.schema}.graph_nodes WHERE agent_id = $1`;
197
+ const params = [query.agentId];
198
+ let paramIndex = 2;
199
+ if (query.types && query.types.length > 0) {
200
+ sql += ` AND type = ANY($${paramIndex++})`;
201
+ params.push(query.types);
202
+ }
203
+ if (query.namePattern) {
204
+ sql += ` AND name ILIKE $${paramIndex++}`;
205
+ params.push(`%${query.namePattern}%`);
206
+ }
207
+ if (query.minConfidence !== undefined) {
208
+ sql += ` AND confidence >= $${paramIndex++}`;
209
+ params.push(query.minConfidence);
210
+ }
211
+ sql += ' ORDER BY access_count DESC, updated_at DESC';
212
+ if (query.limit) {
213
+ sql += ` LIMIT $${paramIndex++}`;
214
+ params.push(query.limit);
215
+ }
216
+ const result = await this.pool.query(sql, params);
217
+ return this.success(result.rows.map((row) => this.rowToNode(row, query.includeEmbedding)));
218
+ }
219
+ async searchNodesSemantic(options) {
220
+ await this.initialize();
221
+ if (!options.vector) {
222
+ return this.failure('searchNodesSemantic requires vector');
223
+ }
224
+ const vectorStr = `[${options.vector.join(',')}]`;
225
+ const limit = options.limit ?? 10;
226
+ const threshold = options.threshold ?? 0.7;
227
+ let sql = `
228
+ SELECT *, 1 - (embedding <=> $1) as score
229
+ FROM ${this.schema}.graph_nodes
230
+ WHERE agent_id = $2 AND embedding IS NOT NULL AND 1 - (embedding <=> $1) >= $3
231
+ `;
232
+ const params = [vectorStr, options.agentId, threshold];
233
+ let paramIndex = 4;
234
+ if (options.entityTypes && options.entityTypes.length > 0) {
235
+ sql += ` AND type = ANY($${paramIndex++})`;
236
+ params.push(options.entityTypes);
237
+ }
238
+ sql += ` ORDER BY embedding <=> $1 LIMIT $${paramIndex}`;
239
+ params.push(limit);
240
+ const result = await this.pool.query(sql, params);
241
+ return this.success(result.rows.map((row) => ({
242
+ ...this.rowToNode(row),
243
+ score: row.score,
244
+ })));
245
+ }
246
+ async addEdge(edge) {
247
+ await this.initialize();
248
+ const id = this.generateId('edge');
249
+ const now = new Date();
250
+ await this.pool.query(`INSERT INTO ${this.schema}.graph_edges
251
+ (id, agent_id, source_node_id, target_node_id, type, label, weight, bidirectional, properties, confidence, source, valid_from, valid_until, metadata, created_at, updated_at)
252
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $15)`, [
253
+ id,
254
+ edge.agentId,
255
+ edge.sourceNodeId,
256
+ edge.targetNodeId,
257
+ edge.type,
258
+ edge.label ?? null,
259
+ edge.weight,
260
+ edge.bidirectional,
261
+ edge.properties,
262
+ edge.confidence,
263
+ edge.source,
264
+ edge.validFrom ?? null,
265
+ edge.validUntil ?? null,
266
+ edge.metadata ?? {},
267
+ now,
268
+ ]);
269
+ return this.success({
270
+ ...edge,
271
+ id,
272
+ createdAt: now,
273
+ updatedAt: now,
274
+ });
275
+ }
276
+ async getEdge(edgeId) {
277
+ await this.initialize();
278
+ const result = await this.pool.query(`SELECT * FROM ${this.schema}.graph_edges WHERE id = $1`, [edgeId]);
279
+ if (result.rows.length === 0)
280
+ return this.success(null);
281
+ return this.success(this.rowToEdge(result.rows[0]));
282
+ }
283
+ async getEdgesBetween(sourceNodeId, targetNodeId) {
284
+ await this.initialize();
285
+ const result = await this.pool.query(`SELECT * FROM ${this.schema}.graph_edges
286
+ WHERE (source_node_id = $1 AND target_node_id = $2)
287
+ OR (bidirectional = TRUE AND source_node_id = $2 AND target_node_id = $1)`, [sourceNodeId, targetNodeId]);
288
+ return this.success(result.rows.map((row) => this.rowToEdge(row)));
289
+ }
290
+ async updateEdge(edgeId, updates) {
291
+ await this.initialize();
292
+ const setClauses = ['updated_at = NOW()'];
293
+ const params = [];
294
+ let paramIndex = 1;
295
+ if (updates.weight !== undefined) {
296
+ setClauses.push(`weight = $${paramIndex++}`);
297
+ params.push(updates.weight);
298
+ }
299
+ if (updates.label !== undefined) {
300
+ setClauses.push(`label = $${paramIndex++}`);
301
+ params.push(updates.label);
302
+ }
303
+ if (updates.properties !== undefined) {
304
+ setClauses.push(`properties = $${paramIndex++}`);
305
+ params.push(updates.properties);
306
+ }
307
+ if (updates.confidence !== undefined) {
308
+ setClauses.push(`confidence = $${paramIndex++}`);
309
+ params.push(updates.confidence);
310
+ }
311
+ if (updates.validFrom !== undefined) {
312
+ setClauses.push(`valid_from = $${paramIndex++}`);
313
+ params.push(updates.validFrom);
314
+ }
315
+ if (updates.validUntil !== undefined) {
316
+ setClauses.push(`valid_until = $${paramIndex++}`);
317
+ params.push(updates.validUntil);
318
+ }
319
+ if (updates.metadata !== undefined) {
320
+ setClauses.push(`metadata = $${paramIndex++}`);
321
+ params.push(updates.metadata);
322
+ }
323
+ params.push(edgeId);
324
+ const result = await this.pool.query(`UPDATE ${this.schema}.graph_edges SET ${setClauses.join(', ')} WHERE id = $${paramIndex} RETURNING *`, params);
325
+ if (result.rows.length === 0) {
326
+ return this.failure(`Edge not found: ${edgeId}`);
327
+ }
328
+ return this.success(this.rowToEdge(result.rows[0]));
329
+ }
330
+ async deleteEdge(edgeId) {
331
+ await this.initialize();
332
+ await this.pool.query(`DELETE FROM ${this.schema}.graph_edges WHERE id = $1`, [edgeId]);
333
+ return this.success(undefined);
334
+ }
335
+ async queryEdges(query) {
336
+ await this.initialize();
337
+ let sql = `SELECT * FROM ${this.schema}.graph_edges WHERE agent_id = $1`;
338
+ const params = [query.agentId];
339
+ let paramIndex = 2;
340
+ if (query.sourceNodeId) {
341
+ sql += ` AND source_node_id = $${paramIndex++}`;
342
+ params.push(query.sourceNodeId);
343
+ }
344
+ if (query.targetNodeId) {
345
+ sql += ` AND target_node_id = $${paramIndex++}`;
346
+ params.push(query.targetNodeId);
347
+ }
348
+ if (query.types && query.types.length > 0) {
349
+ sql += ` AND type = ANY($${paramIndex++})`;
350
+ params.push(query.types);
351
+ }
352
+ if (query.minWeight !== undefined) {
353
+ sql += ` AND weight >= $${paramIndex++}`;
354
+ params.push(query.minWeight);
355
+ }
356
+ if (query.minConfidence !== undefined) {
357
+ sql += ` AND confidence >= $${paramIndex++}`;
358
+ params.push(query.minConfidence);
359
+ }
360
+ if (query.bidirectionalOnly) {
361
+ sql += ' AND bidirectional = TRUE';
362
+ }
363
+ sql += ' ORDER BY weight DESC, confidence DESC';
364
+ if (query.limit) {
365
+ sql += ` LIMIT $${paramIndex++}`;
366
+ params.push(query.limit);
367
+ }
368
+ const result = await this.pool.query(sql, params);
369
+ return this.success(result.rows.map((row) => this.rowToEdge(row)));
370
+ }
371
+ async traverse(options) {
372
+ await this.initialize();
373
+ const visited = new Set();
374
+ const visitedEdges = new Set();
375
+ const paths = [];
376
+ const allNodes = [];
377
+ const allEdges = [];
378
+ const startNodeResult = await this.getNode(options.startNodeId);
379
+ if (!startNodeResult.success || !startNodeResult.data) {
380
+ return this.failure(`Start node not found: ${options.startNodeId}`);
381
+ }
382
+ const startNode = startNodeResult.data;
383
+ visited.add(startNode.id);
384
+ allNodes.push(startNode);
385
+ await this.traverseRecursive(startNode, [], [], 0, options, visited, visitedEdges, paths, allNodes, allEdges);
386
+ return this.success({
387
+ paths,
388
+ visitedNodes: allNodes,
389
+ visitedEdges: allEdges,
390
+ depth: options.maxDepth,
391
+ });
392
+ }
393
+ async traverseRecursive(currentNode, pathNodes, pathEdges, currentDepth, options, visited, visitedEdges, paths, allNodes, allEdges) {
394
+ if (currentDepth >= options.maxDepth) {
395
+ if (pathNodes.length > 0) {
396
+ paths.push({
397
+ nodes: [...pathNodes, currentNode],
398
+ edges: [...pathEdges],
399
+ totalWeight: pathEdges.reduce((sum, e) => sum + e.weight, 0),
400
+ length: pathEdges.length,
401
+ });
402
+ }
403
+ return;
404
+ }
405
+ if (options.limit && paths.length >= options.limit)
406
+ return;
407
+ const neighborsResult = await this.getNeighbors(currentNode.id, options.direction);
408
+ if (!neighborsResult.success)
409
+ return;
410
+ for (const { node, edge } of neighborsResult.data) {
411
+ if (options.edgeTypes && !options.edgeTypes.includes(edge.type))
412
+ continue;
413
+ if (options.minEdgeWeight !== undefined && edge.weight < options.minEdgeWeight)
414
+ continue;
415
+ if (options.minConfidence !== undefined && edge.confidence < options.minConfidence)
416
+ continue;
417
+ if (!visitedEdges.has(edge.id)) {
418
+ visitedEdges.add(edge.id);
419
+ allEdges.push(edge);
420
+ }
421
+ if (!visited.has(node.id)) {
422
+ visited.add(node.id);
423
+ allNodes.push(node);
424
+ await this.traverseRecursive(node, [...pathNodes, currentNode], [...pathEdges, edge], currentDepth + 1, options, visited, visitedEdges, paths, allNodes, allEdges);
425
+ }
426
+ }
427
+ }
428
+ async findShortestPath(agentId, startNodeId, endNodeId, maxDepth = 5) {
429
+ await this.initialize();
430
+ const result = await this.pool.query(`
431
+ WITH RECURSIVE path_search AS (
432
+ SELECT
433
+ source_node_id as start_node,
434
+ target_node_id as end_node,
435
+ ARRAY[source_node_id, target_node_id] as path,
436
+ ARRAY[id] as edge_ids,
437
+ weight as total_weight,
438
+ 1 as depth
439
+ FROM ${this.schema}.graph_edges
440
+ WHERE agent_id = $1 AND source_node_id = $2
441
+
442
+ UNION ALL
443
+
444
+ SELECT
445
+ ps.start_node,
446
+ e.target_node_id,
447
+ ps.path || e.target_node_id,
448
+ ps.edge_ids || e.id,
449
+ ps.total_weight + e.weight,
450
+ ps.depth + 1
451
+ FROM path_search ps
452
+ JOIN ${this.schema}.graph_edges e ON e.source_node_id = ps.end_node
453
+ WHERE e.agent_id = $1
454
+ AND NOT e.target_node_id = ANY(ps.path)
455
+ AND ps.depth < $4
456
+ )
457
+ SELECT path, edge_ids, total_weight
458
+ FROM path_search
459
+ WHERE end_node = $3
460
+ ORDER BY depth, total_weight
461
+ LIMIT 1
462
+ `, [agentId, startNodeId, endNodeId, maxDepth]);
463
+ if (result.rows.length === 0)
464
+ return this.success(null);
465
+ const row = result.rows[0];
466
+ const nodeIds = row.path;
467
+ const edgeIds = row.edge_ids;
468
+ const nodes = [];
469
+ const edges = [];
470
+ for (const nodeId of nodeIds) {
471
+ const nodeResult = await this.getNode(nodeId);
472
+ if (nodeResult.success && nodeResult.data) {
473
+ nodes.push(nodeResult.data);
474
+ }
475
+ }
476
+ for (const edgeId of edgeIds) {
477
+ const edgeResult = await this.getEdge(edgeId);
478
+ if (edgeResult.success && edgeResult.data) {
479
+ edges.push(edgeResult.data);
480
+ }
481
+ }
482
+ return this.success({
483
+ nodes,
484
+ edges,
485
+ totalWeight: row.total_weight,
486
+ length: edges.length,
487
+ });
488
+ }
489
+ async getNeighbors(nodeId, direction = 'both') {
490
+ await this.initialize();
491
+ let sql;
492
+ const params = [nodeId];
493
+ if (direction === 'outgoing') {
494
+ sql = `
495
+ SELECT e.*, n.*,
496
+ e.id as edge_id, e.agent_id as edge_agent_id, e.type as edge_type,
497
+ e.source_node_id, e.target_node_id, e.label, e.weight, e.bidirectional,
498
+ e.properties as edge_properties, e.confidence as edge_confidence,
499
+ e.source as edge_source, e.valid_from, e.valid_until,
500
+ e.metadata as edge_metadata, e.created_at as edge_created_at, e.updated_at as edge_updated_at
501
+ FROM ${this.schema}.graph_edges e
502
+ JOIN ${this.schema}.graph_nodes n ON n.id = e.target_node_id
503
+ WHERE e.source_node_id = $1
504
+ `;
505
+ }
506
+ else if (direction === 'incoming') {
507
+ sql = `
508
+ SELECT e.*, n.*,
509
+ e.id as edge_id, e.agent_id as edge_agent_id, e.type as edge_type,
510
+ e.source_node_id, e.target_node_id, e.label, e.weight, e.bidirectional,
511
+ e.properties as edge_properties, e.confidence as edge_confidence,
512
+ e.source as edge_source, e.valid_from, e.valid_until,
513
+ e.metadata as edge_metadata, e.created_at as edge_created_at, e.updated_at as edge_updated_at
514
+ FROM ${this.schema}.graph_edges e
515
+ JOIN ${this.schema}.graph_nodes n ON n.id = e.source_node_id
516
+ WHERE e.target_node_id = $1
517
+ `;
518
+ }
519
+ else {
520
+ sql = `
521
+ SELECT e.*, n.*,
522
+ e.id as edge_id, e.agent_id as edge_agent_id, e.type as edge_type,
523
+ e.source_node_id, e.target_node_id, e.label, e.weight, e.bidirectional,
524
+ e.properties as edge_properties, e.confidence as edge_confidence,
525
+ e.source as edge_source, e.valid_from, e.valid_until,
526
+ e.metadata as edge_metadata, e.created_at as edge_created_at, e.updated_at as edge_updated_at
527
+ FROM ${this.schema}.graph_edges e
528
+ JOIN ${this.schema}.graph_nodes n ON (
529
+ (e.source_node_id = $1 AND n.id = e.target_node_id) OR
530
+ (e.target_node_id = $1 AND n.id = e.source_node_id)
531
+ )
532
+ WHERE e.source_node_id = $1 OR e.target_node_id = $1
533
+ `;
534
+ }
535
+ const result = await this.pool.query(sql, params);
536
+ return this.success(result.rows.map((row) => ({
537
+ node: this.rowToNode(row),
538
+ edge: this.rowToEdgeFromJoin(row),
539
+ })));
540
+ }
541
+ async mergeNodes(targetNodeId, sourceNodeIds) {
542
+ await this.initialize();
543
+ for (const sourceId of sourceNodeIds) {
544
+ await this.pool.query(`UPDATE ${this.schema}.graph_edges
545
+ SET source_node_id = $1 WHERE source_node_id = $2`, [targetNodeId, sourceId]);
546
+ await this.pool.query(`UPDATE ${this.schema}.graph_edges
547
+ SET target_node_id = $1 WHERE target_node_id = $2`, [targetNodeId, sourceId]);
548
+ const sourceNode = await this.getNode(sourceId);
549
+ if (sourceNode.success && sourceNode.data) {
550
+ await this.pool.query(`UPDATE ${this.schema}.graph_nodes
551
+ SET aliases = array_cat(aliases, $1::TEXT[])
552
+ WHERE id = $2`, [[sourceNode.data.name, ...sourceNode.data.aliases], targetNodeId]);
553
+ }
554
+ await this.deleteNode(sourceId);
555
+ }
556
+ const mergedNode = await this.getNode(targetNodeId);
557
+ if (!mergedNode.success || !mergedNode.data) {
558
+ return this.failure(`Target node not found: ${targetNodeId}`);
559
+ }
560
+ return this.success(mergedNode.data);
561
+ }
562
+ async clearGraph(agentId) {
563
+ await this.initialize();
564
+ await this.pool.query(`DELETE FROM ${this.schema}.graph_nodes WHERE agent_id = $1`, [agentId]);
565
+ return this.success(undefined);
566
+ }
567
+ async getGraphStats(agentId) {
568
+ await this.initialize();
569
+ const nodeCountResult = await this.pool.query(`SELECT COUNT(*) as count FROM ${this.schema}.graph_nodes WHERE agent_id = $1`, [agentId]);
570
+ const edgeCountResult = await this.pool.query(`SELECT COUNT(*) as count FROM ${this.schema}.graph_edges WHERE agent_id = $1`, [agentId]);
571
+ const nodesByTypeResult = await this.pool.query(`SELECT type, COUNT(*) as count FROM ${this.schema}.graph_nodes WHERE agent_id = $1 GROUP BY type`, [agentId]);
572
+ const edgesByTypeResult = await this.pool.query(`SELECT type, COUNT(*) as count FROM ${this.schema}.graph_edges WHERE agent_id = $1 GROUP BY type`, [agentId]);
573
+ const nodeCount = parseInt(nodeCountResult.rows[0]?.count ?? '0', 10);
574
+ const edgeCount = parseInt(edgeCountResult.rows[0]?.count ?? '0', 10);
575
+ const nodesByType = {};
576
+ for (const row of nodesByTypeResult.rows) {
577
+ nodesByType[row.type] = parseInt(row.count, 10);
578
+ }
579
+ const edgesByType = {};
580
+ for (const row of edgesByTypeResult.rows) {
581
+ edgesByType[row.type] = parseInt(row.count, 10);
582
+ }
583
+ return this.success({
584
+ nodeCount,
585
+ edgeCount,
586
+ nodesByType,
587
+ edgesByType,
588
+ averageEdgesPerNode: nodeCount > 0 ? edgeCount / nodeCount : 0,
589
+ maxDepth: 0,
590
+ });
591
+ }
592
+ rowToNode(row, includeEmbedding = false) {
593
+ return {
594
+ id: row.id,
595
+ agentId: row.agent_id,
596
+ type: row.type,
597
+ name: row.name,
598
+ aliases: row.aliases ?? [],
599
+ description: row.description,
600
+ properties: row.properties ?? {},
601
+ embedding: includeEmbedding ? row.embedding : undefined,
602
+ confidence: row.confidence,
603
+ source: row.source,
604
+ createdAt: new Date(row.created_at),
605
+ updatedAt: new Date(row.updated_at),
606
+ lastAccessedAt: new Date(row.last_accessed_at),
607
+ accessCount: row.access_count,
608
+ metadata: row.metadata,
609
+ };
610
+ }
611
+ rowToEdge(row) {
612
+ return {
613
+ id: row.id,
614
+ agentId: row.agent_id,
615
+ sourceNodeId: row.source_node_id,
616
+ targetNodeId: row.target_node_id,
617
+ type: row.type,
618
+ label: row.label,
619
+ weight: row.weight,
620
+ bidirectional: row.bidirectional,
621
+ properties: row.properties ?? {},
622
+ confidence: row.confidence,
623
+ source: row.source,
624
+ createdAt: new Date(row.created_at),
625
+ updatedAt: new Date(row.updated_at),
626
+ validFrom: row.valid_from ? new Date(row.valid_from) : undefined,
627
+ validUntil: row.valid_until ? new Date(row.valid_until) : undefined,
628
+ metadata: row.metadata,
629
+ };
630
+ }
631
+ rowToEdgeFromJoin(row) {
632
+ return {
633
+ id: row.edge_id,
634
+ agentId: row.edge_agent_id,
635
+ sourceNodeId: row.source_node_id,
636
+ targetNodeId: row.target_node_id,
637
+ type: row.edge_type,
638
+ label: row.label,
639
+ weight: row.weight,
640
+ bidirectional: row.bidirectional,
641
+ properties: row.edge_properties ?? {},
642
+ confidence: row.edge_confidence,
643
+ source: row.edge_source,
644
+ createdAt: new Date(row.edge_created_at),
645
+ updatedAt: new Date(row.edge_updated_at),
646
+ validFrom: row.valid_from ? new Date(row.valid_from) : undefined,
647
+ validUntil: row.valid_until ? new Date(row.valid_until) : undefined,
648
+ metadata: row.edge_metadata,
649
+ };
650
+ }
651
+ }
652
+ //# sourceMappingURL=graph-adapter.js.map