n8n-nodes-engram 0.2.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/LICENSE +661 -0
- package/README.md +334 -0
- package/dist/community/CommunityDetector.d.ts +11 -0
- package/dist/community/CommunityDetector.js +126 -0
- package/dist/community/CommunityDetector.js.map +1 -0
- package/dist/community/CommunitySummarizer.d.ts +8 -0
- package/dist/community/CommunitySummarizer.js +56 -0
- package/dist/community/CommunitySummarizer.js.map +1 -0
- package/dist/community/index.d.ts +2 -0
- package/dist/community/index.js +8 -0
- package/dist/community/index.js.map +1 -0
- package/dist/credentials/EngramExtractionApi.credentials.d.ts +8 -0
- package/dist/credentials/EngramExtractionApi.credentials.js +41 -0
- package/dist/credentials/EngramExtractionApi.credentials.js.map +1 -0
- package/dist/credentials/EngramNeo4jApi.credentials.d.ts +8 -0
- package/dist/credentials/EngramNeo4jApi.credentials.js +59 -0
- package/dist/credentials/EngramNeo4jApi.credentials.js.map +1 -0
- package/dist/descriptions.d.ts +4 -0
- package/dist/descriptions.js +41 -0
- package/dist/descriptions.js.map +1 -0
- package/dist/embeddings/EmbeddingService.d.ts +24 -0
- package/dist/embeddings/EmbeddingService.js +64 -0
- package/dist/embeddings/EmbeddingService.js.map +1 -0
- package/dist/embeddings/cosine.d.ts +1 -0
- package/dist/embeddings/cosine.js +21 -0
- package/dist/embeddings/cosine.js.map +1 -0
- package/dist/embeddings/index.d.ts +2 -0
- package/dist/embeddings/index.js +8 -0
- package/dist/embeddings/index.js.map +1 -0
- package/dist/extraction/ContradictionDetector.d.ts +11 -0
- package/dist/extraction/ContradictionDetector.js +35 -0
- package/dist/extraction/ContradictionDetector.js.map +1 -0
- package/dist/extraction/EntityDeduplicator.d.ts +17 -0
- package/dist/extraction/EntityDeduplicator.js +39 -0
- package/dist/extraction/EntityDeduplicator.js.map +1 -0
- package/dist/extraction/EntityExtractor.d.ts +11 -0
- package/dist/extraction/EntityExtractor.js +33 -0
- package/dist/extraction/EntityExtractor.js.map +1 -0
- package/dist/extraction/ExtractionPipeline.d.ts +24 -0
- package/dist/extraction/ExtractionPipeline.js +126 -0
- package/dist/extraction/ExtractionPipeline.js.map +1 -0
- package/dist/extraction/LlmClient.d.ts +36 -0
- package/dist/extraction/LlmClient.js +73 -0
- package/dist/extraction/LlmClient.js.map +1 -0
- package/dist/extraction/RelationshipExtractor.d.ts +12 -0
- package/dist/extraction/RelationshipExtractor.js +38 -0
- package/dist/extraction/RelationshipExtractor.js.map +1 -0
- package/dist/extraction/index.d.ts +6 -0
- package/dist/extraction/index.js +16 -0
- package/dist/extraction/index.js.map +1 -0
- package/dist/extraction/prompts.d.ts +16 -0
- package/dist/extraction/prompts.js +101 -0
- package/dist/extraction/prompts.js.map +1 -0
- package/dist/memory/EngramChatMemory.d.ts +42 -0
- package/dist/memory/EngramChatMemory.js +162 -0
- package/dist/memory/EngramChatMemory.js.map +1 -0
- package/dist/memory/EngramChatMessageHistory.d.ts +22 -0
- package/dist/memory/EngramChatMessageHistory.js +72 -0
- package/dist/memory/EngramChatMessageHistory.js.map +1 -0
- package/dist/memory/index.d.ts +2 -0
- package/dist/memory/index.js +8 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/nodes/EngramAdmin/EngramAdmin.node.d.ts +5 -0
- package/dist/nodes/EngramAdmin/EngramAdmin.node.js +798 -0
- package/dist/nodes/EngramAdmin/EngramAdmin.node.js.map +1 -0
- package/dist/nodes/EngramAdmin/engram-admin.png +0 -0
- package/dist/nodes/EngramExplorer/EngramExplorer.node.d.ts +5 -0
- package/dist/nodes/EngramExplorer/EngramExplorer.node.js +932 -0
- package/dist/nodes/EngramExplorer/EngramExplorer.node.js.map +1 -0
- package/dist/nodes/EngramExplorer/engram-explorer.png +0 -0
- package/dist/nodes/EngramMemory/EngramMemory.node.d.ts +10 -0
- package/dist/nodes/EngramMemory/EngramMemory.node.js +462 -0
- package/dist/nodes/EngramMemory/EngramMemory.node.js.map +1 -0
- package/dist/nodes/EngramMemory/engram.png +0 -0
- package/dist/nodes/EngramTrigger/EngramTrigger.node.d.ts +5 -0
- package/dist/nodes/EngramTrigger/EngramTrigger.node.js +146 -0
- package/dist/nodes/EngramTrigger/EngramTrigger.node.js.map +1 -0
- package/dist/nodes/EngramTrigger/engram-trigger.png +0 -0
- package/dist/schemas/Community.schema.d.ts +656 -0
- package/dist/schemas/Community.schema.js +26 -0
- package/dist/schemas/Community.schema.js.map +1 -0
- package/dist/schemas/EntityEdge.schema.d.ts +86 -0
- package/dist/schemas/EntityEdge.schema.js +34 -0
- package/dist/schemas/EntityEdge.schema.js.map +1 -0
- package/dist/schemas/EntityNode.schema.d.ts +56 -0
- package/dist/schemas/EntityNode.schema.js +24 -0
- package/dist/schemas/EntityNode.schema.js.map +1 -0
- package/dist/schemas/EpisodicNode.schema.d.ts +53 -0
- package/dist/schemas/EpisodicNode.schema.js +23 -0
- package/dist/schemas/EpisodicNode.schema.js.map +1 -0
- package/dist/schemas/GraphData.schema.d.ts +220 -0
- package/dist/schemas/GraphData.schema.js +25 -0
- package/dist/schemas/GraphData.schema.js.map +1 -0
- package/dist/schemas/index.d.ts +5 -0
- package/dist/schemas/index.js +20 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/search/HybridSearchEngine.d.ts +31 -0
- package/dist/search/HybridSearchEngine.js +140 -0
- package/dist/search/HybridSearchEngine.js.map +1 -0
- package/dist/search/MinisearchProvider.d.ts +20 -0
- package/dist/search/MinisearchProvider.js +77 -0
- package/dist/search/MinisearchProvider.js.map +1 -0
- package/dist/search/TextSearchProvider.d.ts +20 -0
- package/dist/search/TextSearchProvider.js +3 -0
- package/dist/search/TextSearchProvider.js.map +1 -0
- package/dist/search/index.d.ts +3 -0
- package/dist/search/index.js +8 -0
- package/dist/search/index.js.map +1 -0
- package/dist/storage/GraphologyStorage.d.ts +42 -0
- package/dist/storage/GraphologyStorage.js +665 -0
- package/dist/storage/GraphologyStorage.js.map +1 -0
- package/dist/storage/IGraphStorage.d.ts +64 -0
- package/dist/storage/IGraphStorage.js +3 -0
- package/dist/storage/IGraphStorage.js.map +1 -0
- package/dist/storage/Neo4jStorage.d.ts +45 -0
- package/dist/storage/Neo4jStorage.js +949 -0
- package/dist/storage/Neo4jStorage.js.map +1 -0
- package/dist/storage/StorageFactory.d.ts +14 -0
- package/dist/storage/StorageFactory.js +26 -0
- package/dist/storage/StorageFactory.js.map +1 -0
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.js +8 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/traversal/EpisodeTraverser.d.ts +10 -0
- package/dist/traversal/EpisodeTraverser.js +46 -0
- package/dist/traversal/EpisodeTraverser.js.map +1 -0
- package/dist/traversal/GraphTraverser.d.ts +24 -0
- package/dist/traversal/GraphTraverser.js +89 -0
- package/dist/traversal/GraphTraverser.js.map +1 -0
- package/dist/traversal/index.d.ts +2 -0
- package/dist/traversal/index.js +8 -0
- package/dist/traversal/index.js.map +1 -0
- package/dist/utils/descriptions.d.ts +6 -0
- package/dist/utils/descriptions.js +95 -0
- package/dist/utils/descriptions.js.map +1 -0
- package/dist/utils/helpers.d.ts +23 -0
- package/dist/utils/helpers.js +146 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/logWrapper.d.ts +26 -0
- package/dist/utils/logWrapper.js +300 -0
- package/dist/utils/logWrapper.js.map +1 -0
- package/dist/utils/sharedFields.d.ts +6 -0
- package/dist/utils/sharedFields.js +121 -0
- package/dist/utils/sharedFields.js.map +1 -0
- package/dist/utils/temporal.d.ts +22 -0
- package/dist/utils/temporal.js +44 -0
- package/dist/utils/temporal.js.map +1 -0
- package/dist/utils/tracing.d.ts +7 -0
- package/dist/utils/tracing.js +20 -0
- package/dist/utils/tracing.js.map +1 -0
- package/dist/utils/uuid.d.ts +2 -0
- package/dist/utils/uuid.js +13 -0
- package/dist/utils/uuid.js.map +1 -0
- package/package.json +108 -0
package/README.md
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/images/logo.png" alt="Engram" width="120" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">n8n-nodes-engram</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Knowledge graph memory for n8n AI agents</strong><br/>
|
|
9
|
+
Persistent memory with entity extraction, temporal fact tracking, community detection, graph traversal, and hybrid search.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://github.com/casistack/n8n-nodes-engram/actions/workflows/ci.yml">
|
|
14
|
+
<img src="https://github.com/casistack/n8n-nodes-engram/actions/workflows/ci.yml/badge.svg" alt="CI" />
|
|
15
|
+
</a>
|
|
16
|
+
<a href="https://www.npmjs.com/package/n8n-nodes-engram">
|
|
17
|
+
<img src="https://img.shields.io/npm/v/n8n-nodes-engram.svg" alt="npm version" />
|
|
18
|
+
</a>
|
|
19
|
+
<a href="https://github.com/casistack/n8n-nodes-engram/blob/main/LICENSE">
|
|
20
|
+
<img src="https://img.shields.io/badge/license-AGPL--3.0-blue.svg" alt="License: AGPL-3.0" />
|
|
21
|
+
</a>
|
|
22
|
+
<img src="https://img.shields.io/badge/node-%3E%3D18.10-brightgreen.svg" alt="Node.js" />
|
|
23
|
+
<img src="https://img.shields.io/badge/n8n-community%20node-ff6d5a.svg" alt="n8n community node" />
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
<p align="center">
|
|
27
|
+
<a href="#installation">Installation</a> ·
|
|
28
|
+
<a href="#node-reference">Nodes</a> ·
|
|
29
|
+
<a href="#storage-backends">Storage</a> ·
|
|
30
|
+
<a href="#knowledge-extraction">Extraction</a> ·
|
|
31
|
+
<a href="#search">Search</a> ·
|
|
32
|
+
<a href="#data-storage--security">Security</a> ·
|
|
33
|
+
<a href="#development">Development</a>
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
> **Note:** This is a community node. It is not officially supported by n8n. Use at your own discretion.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Overview
|
|
43
|
+
|
|
44
|
+
Engram gives your n8n AI agents a **knowledge graph memory**. Instead of losing context between conversations, agents build and query a persistent graph of entities (people, organizations, concepts) and the relationships between them.
|
|
45
|
+
|
|
46
|
+
Every conversation is stored as an episode. An optional LLM extraction pipeline identifies entities and facts from dialogue, building a growing knowledge graph. When the agent receives a new message, Engram searches the graph for relevant facts and injects them as context—giving the agent long-term memory that goes beyond simple chat history.
|
|
47
|
+
|
|
48
|
+
### Highlights
|
|
49
|
+
|
|
50
|
+
| | Feature | Description |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| **4** | n8n Nodes | Memory, Explorer, Admin, Trigger |
|
|
53
|
+
| **2** | Storage Backends | Embedded (zero-setup) or Neo4j (production) |
|
|
54
|
+
| **5** | Extraction Stages | Entity, dedup, relationships, contradictions, embeddings |
|
|
55
|
+
| **3** | Search Modes | Full-text, vector, hybrid RRF fusion |
|
|
56
|
+
| **169** | Tests | Unit + integration across 17 test suites |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Architecture
|
|
61
|
+
|
|
62
|
+
<p align="center">
|
|
63
|
+
<img src="docs/images/architecture.svg" alt="Engram Architecture" width="780" />
|
|
64
|
+
</p>
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Installation
|
|
69
|
+
|
|
70
|
+
### Via n8n Community Nodes
|
|
71
|
+
|
|
72
|
+
1. Go to **Settings > Community Nodes** in your n8n instance
|
|
73
|
+
2. Enter `n8n-nodes-engram`
|
|
74
|
+
3. Click **Install**
|
|
75
|
+
|
|
76
|
+
### Manual
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
cd ~/.n8n
|
|
80
|
+
npm install n8n-nodes-engram
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Quick Start
|
|
86
|
+
|
|
87
|
+
### Minimal Setup (No LLM Required)
|
|
88
|
+
|
|
89
|
+
1. Add an **Engram Memory** node to your AI Agent workflow
|
|
90
|
+
2. Connect it to the agent's Memory input
|
|
91
|
+
3. Set **Storage Backend** to `Embedded (Graphology)`
|
|
92
|
+
4. Leave **Knowledge Extraction** as `Disabled`
|
|
93
|
+
|
|
94
|
+
Your agent now has persistent conversation history stored as episodic memory.
|
|
95
|
+
|
|
96
|
+
### Full Setup (With Extraction)
|
|
97
|
+
|
|
98
|
+
1. Create an **Engram Extraction LLM** credential:
|
|
99
|
+
- **Base URL**: OpenAI-compatible endpoint (e.g. `https://api.openai.com/v1`)
|
|
100
|
+
- **API Key**: Your API key
|
|
101
|
+
2. Add an **Engram Memory** node, enable **Knowledge Extraction**
|
|
102
|
+
3. Select an extraction model (e.g. `gpt-4o-mini`)
|
|
103
|
+
4. Optionally enable **Semantic Search (Embeddings)** with an embedding model
|
|
104
|
+
5. Optionally enable **Graph Traversal (BFS)** for context enrichment
|
|
105
|
+
|
|
106
|
+
The extraction pipeline automatically identifies entities and relationships from conversations and builds a queryable knowledge graph.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Node Reference
|
|
111
|
+
|
|
112
|
+
### Engram Memory
|
|
113
|
+
|
|
114
|
+
> AI Memory node—connects to the AI Agent memory input.
|
|
115
|
+
|
|
116
|
+
On each conversation turn, Engram Memory:
|
|
117
|
+
|
|
118
|
+
- **Loads** relevant facts from the knowledge graph as system context, plus recent chat history
|
|
119
|
+
- **Saves** messages as episodes, optionally running the full extraction pipeline
|
|
120
|
+
|
|
121
|
+
| Setting | Description | Default |
|
|
122
|
+
| --- | --- | --- |
|
|
123
|
+
| Storage Backend | Embedded (Graphology) or Neo4j | Embedded |
|
|
124
|
+
| Knowledge Extraction | LLM-powered entity extraction | Disabled |
|
|
125
|
+
| Semantic Search | Vector embeddings for hybrid search | Disabled |
|
|
126
|
+
| Graph Traversal | BFS enrichment from matched entities | Disabled |
|
|
127
|
+
| Context Window | Recent turns to include | 10 |
|
|
128
|
+
| Max Facts per Query | Facts injected as context | 10 |
|
|
129
|
+
| Min Relevance Score | Threshold for inclusion (0–1) | 0.5 |
|
|
130
|
+
| Retention Policy | Episode lifecycle management | Forever |
|
|
131
|
+
|
|
132
|
+
### Engram Explorer
|
|
133
|
+
|
|
134
|
+
> Regular node—CRUD operations on the knowledge graph.
|
|
135
|
+
|
|
136
|
+
| Resource | Operations |
|
|
137
|
+
| --- | --- |
|
|
138
|
+
| **Entity** | Create, Get, Get by Name, List, Search, Update, Delete |
|
|
139
|
+
| **Relationship** | Create, Get, Get Between, Get for Entity, Search, Update, Delete |
|
|
140
|
+
| **Episode** | Get, Get Recent, Get Count |
|
|
141
|
+
| **Traversal** | BFS from Entity, BFS from Episodes |
|
|
142
|
+
|
|
143
|
+
### Engram Admin
|
|
144
|
+
|
|
145
|
+
> Regular node—administration and analysis.
|
|
146
|
+
|
|
147
|
+
| Category | Operations |
|
|
148
|
+
| --- | --- |
|
|
149
|
+
| **Monitoring** | Stats, List Groups, Group Stats |
|
|
150
|
+
| **Lifecycle** | Apply Retention, Clear Group, Bulk Clear, Clear All |
|
|
151
|
+
| **Hygiene** | Orphaned Entities, Duplicate Entities, Expire Stale Edges |
|
|
152
|
+
| **Analysis** | Detect Communities |
|
|
153
|
+
| **Portability** | Export (JSON), Import (JSON) |
|
|
154
|
+
|
|
155
|
+
### Engram Trigger
|
|
156
|
+
|
|
157
|
+
> Polling trigger—fires when new entities, relationships, or episodes appear in the graph.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Storage Backends
|
|
162
|
+
|
|
163
|
+
| | Embedded (Graphology) | Neo4j |
|
|
164
|
+
| --- | --- | --- |
|
|
165
|
+
| **Setup** | Zero configuration | Requires Neo4j instance |
|
|
166
|
+
| **Persistence** | JSON file on disk | Neo4j database |
|
|
167
|
+
| **Vector search** | Brute-force cosine similarity | Brute-force cosine similarity |
|
|
168
|
+
| **Best for** | Development, single-instance | Production, multi-instance |
|
|
169
|
+
| **Scaling** | Single n8n instance | Independent of n8n lifecycle |
|
|
170
|
+
|
|
171
|
+
Both backends implement the same `IGraphStorage` interface. All features work identically on either backend.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Knowledge Extraction
|
|
176
|
+
|
|
177
|
+
When enabled, the extraction pipeline processes each conversation turn:
|
|
178
|
+
|
|
179
|
+
```text
|
|
180
|
+
User message + AI response
|
|
181
|
+
|
|
|
182
|
+
Entity Extractor ── identifies people, orgs, locations, concepts
|
|
183
|
+
|
|
|
184
|
+
Entity Deduplicator ── merges "Bob Smith" with "Bob"
|
|
185
|
+
|
|
|
186
|
+
Relationship Extractor ── extracts facts ("Alice works at Acme")
|
|
187
|
+
|
|
|
188
|
+
Contradiction Detector ── flags conflicting facts
|
|
189
|
+
|
|
|
190
|
+
Embedding Generator ── (optional) vectors for semantic search
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Supported providers**: Any OpenAI-compatible API—OpenAI, OpenRouter, Ollama, LM Studio, Together AI, and others.
|
|
194
|
+
|
|
195
|
+
**Configurable entity types**: `person`, `organization`, `location`, `concept`, `event`, or custom types.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Search
|
|
200
|
+
|
|
201
|
+
| Mode | Description | Requirements |
|
|
202
|
+
| --- | --- | --- |
|
|
203
|
+
| **Full-text** | Keyword search on names, summaries, and facts | None |
|
|
204
|
+
| **Vector** | Cosine similarity on embedding vectors | Embeddings enabled |
|
|
205
|
+
| **Hybrid RRF** | Reciprocal Rank Fusion combining text + vector | Embeddings enabled |
|
|
206
|
+
|
|
207
|
+
Hybrid search automatically activates when both text and vector search are available.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Community Detection
|
|
212
|
+
|
|
213
|
+
Clusters related entities using **label propagation**. Communities are computed on demand via **Engram Admin > Detect Communities** and include member entities, key entities ranked by connectivity, and optional LLM-generated summaries.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Graph Traversal
|
|
218
|
+
|
|
219
|
+
BFS (breadth-first search) walks the knowledge graph outward from seed entities, collecting connected entities and relationships within a configurable hop limit.
|
|
220
|
+
|
|
221
|
+
- **BFS from Entity**: Start from specific entity UUIDs
|
|
222
|
+
- **BFS from Episodes**: Start from entities referenced in recent episodes
|
|
223
|
+
- **Automatic enrichment**: When enabled on the Memory node, a shallow BFS (default: 1 hop) runs after each search to enrich agent context
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Data Storage & Security
|
|
228
|
+
|
|
229
|
+
Engram stores conversation data and extracted knowledge. You should understand where this data lives before deploying to production.
|
|
230
|
+
|
|
231
|
+
**Embedded backend:**
|
|
232
|
+
|
|
233
|
+
- Data is stored as a JSON file at `engram-data/{workflowId}-engram.json` inside your n8n data directory
|
|
234
|
+
- The file contains all entities, relationships, episodes, and embeddings in plain text
|
|
235
|
+
- Backups: copy the JSON file
|
|
236
|
+
|
|
237
|
+
**Neo4j backend:**
|
|
238
|
+
|
|
239
|
+
- Data is stored in your Neo4j database instance
|
|
240
|
+
- Engram does not manage Neo4j authentication, encryption, or access control—configure these in Neo4j directly
|
|
241
|
+
- Credentials (URI, username, password) are stored in n8n's encrypted credential store
|
|
242
|
+
|
|
243
|
+
**LLM API calls:**
|
|
244
|
+
|
|
245
|
+
- When extraction is enabled, conversation content is sent to the configured LLM provider for entity/relationship extraction
|
|
246
|
+
- Embedding generation sends entity names and facts to the configured embedding model
|
|
247
|
+
- No data is sent to any external service unless you explicitly enable extraction and configure an API credential
|
|
248
|
+
|
|
249
|
+
**General:**
|
|
250
|
+
|
|
251
|
+
- Engram does not phone home, collect telemetry, or make network calls beyond the LLM API you configure
|
|
252
|
+
- All data stays on your infrastructure
|
|
253
|
+
- Group IDs isolate data between different conversations/users
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Credentials
|
|
258
|
+
|
|
259
|
+
### Engram Extraction LLM
|
|
260
|
+
|
|
261
|
+
| Field | Description |
|
|
262
|
+
| --- | --- |
|
|
263
|
+
| Base URL | OpenAI-compatible API base URL |
|
|
264
|
+
| API Key | API key for the LLM provider |
|
|
265
|
+
|
|
266
|
+
Used for entity extraction, community summaries, and embedding generation.
|
|
267
|
+
|
|
268
|
+
### Engram Neo4j Connection
|
|
269
|
+
|
|
270
|
+
| Field | Description |
|
|
271
|
+
| --- | --- |
|
|
272
|
+
| URI | Neo4j connection URI (e.g. `bolt://localhost:7687`) |
|
|
273
|
+
| Username | Neo4j username |
|
|
274
|
+
| Password | Neo4j password |
|
|
275
|
+
| Database | Database name (default: `neo4j`) |
|
|
276
|
+
|
|
277
|
+
Required only with the Neo4j storage backend.
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Development
|
|
282
|
+
|
|
283
|
+
### Prerequisites
|
|
284
|
+
|
|
285
|
+
- Node.js >= 18.10
|
|
286
|
+
- npm
|
|
287
|
+
|
|
288
|
+
### Setup
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
git clone https://github.com/casistack/n8n-nodes-engram.git
|
|
292
|
+
cd n8n-nodes-engram
|
|
293
|
+
npm install
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Commands
|
|
297
|
+
|
|
298
|
+
| Command | Description |
|
|
299
|
+
| --- | --- |
|
|
300
|
+
| `npm run build` | TypeScript compilation + icon build |
|
|
301
|
+
| `npm run lint` | ESLint |
|
|
302
|
+
| `npm run format` | Prettier (write) |
|
|
303
|
+
| `npm run format:check` | Prettier (check) |
|
|
304
|
+
| `npm run type-check` | TypeScript type checking |
|
|
305
|
+
| `npm test` | Run all tests |
|
|
306
|
+
| `npm run test:coverage` | Coverage report |
|
|
307
|
+
|
|
308
|
+
### Git Hooks (Husky)
|
|
309
|
+
|
|
310
|
+
| Hook | Checks |
|
|
311
|
+
| --- | --- |
|
|
312
|
+
| `pre-commit` | ESLint, Prettier, TypeScript type-check |
|
|
313
|
+
| `pre-push` | Build, full test suite |
|
|
314
|
+
|
|
315
|
+
### CI/CD
|
|
316
|
+
|
|
317
|
+
- **Pull requests**: Lint, type-check, test across Node 18/20/22
|
|
318
|
+
- **Releases**: Automated npm publish on GitHub Release
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Support
|
|
323
|
+
|
|
324
|
+
If you find Engram useful, consider supporting the project:
|
|
325
|
+
|
|
326
|
+
<a href="https://www.buymeacoffee.com/cassistack" target="_blank">
|
|
327
|
+
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="40" />
|
|
328
|
+
</a>
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## License
|
|
333
|
+
|
|
334
|
+
[AGPL-3.0](LICENSE)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IGraphStorage } from '../storage/IGraphStorage';
|
|
2
|
+
import type { CommunityDetectionResult } from '../schemas/Community.schema';
|
|
3
|
+
export interface CommunityDetectionOptions {
|
|
4
|
+
minCommunitySize?: number;
|
|
5
|
+
maxIterations?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class CommunityDetector {
|
|
8
|
+
private storage;
|
|
9
|
+
constructor(storage: IGraphStorage);
|
|
10
|
+
detect(groupId: string, options?: CommunityDetectionOptions): Promise<CommunityDetectionResult>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CommunityDetector = void 0;
|
|
4
|
+
class CommunityDetector {
|
|
5
|
+
constructor(storage) {
|
|
6
|
+
this.storage = storage;
|
|
7
|
+
}
|
|
8
|
+
async detect(groupId, options) {
|
|
9
|
+
var _a, _b, _c, _d;
|
|
10
|
+
const minSize = (_a = options === null || options === void 0 ? void 0 : options.minCommunitySize) !== null && _a !== void 0 ? _a : 2;
|
|
11
|
+
const maxIter = (_b = options === null || options === void 0 ? void 0 : options.maxIterations) !== null && _b !== void 0 ? _b : 10;
|
|
12
|
+
const entities = await this.storage.listEntities(groupId);
|
|
13
|
+
if (entities.length === 0) {
|
|
14
|
+
return {
|
|
15
|
+
communities: [],
|
|
16
|
+
total_entities: 0,
|
|
17
|
+
unclustered_entities: 0,
|
|
18
|
+
detection_method: 'label_propagation',
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const adjacency = new Map();
|
|
22
|
+
const edgeMap = new Map();
|
|
23
|
+
for (const entity of entities) {
|
|
24
|
+
adjacency.set(entity.uuid, new Set());
|
|
25
|
+
edgeMap.set(entity.uuid, []);
|
|
26
|
+
}
|
|
27
|
+
for (const entity of entities) {
|
|
28
|
+
const edges = await this.storage.getEdgesForEntity(entity.uuid);
|
|
29
|
+
edgeMap.set(entity.uuid, edges);
|
|
30
|
+
for (const edge of edges) {
|
|
31
|
+
if (edge.expired_at)
|
|
32
|
+
continue;
|
|
33
|
+
const neighbor = edge.source_node_uuid === entity.uuid ? edge.target_node_uuid : edge.source_node_uuid;
|
|
34
|
+
if (adjacency.has(neighbor)) {
|
|
35
|
+
adjacency.get(entity.uuid).add(neighbor);
|
|
36
|
+
adjacency.get(neighbor).add(entity.uuid);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const labels = new Map();
|
|
41
|
+
for (const entity of entities) {
|
|
42
|
+
labels.set(entity.uuid, entity.uuid);
|
|
43
|
+
}
|
|
44
|
+
const entityUuids = entities.map((e) => e.uuid);
|
|
45
|
+
for (let iter = 0; iter < maxIter; iter++) {
|
|
46
|
+
let changed = false;
|
|
47
|
+
const sorted = [...entityUuids].sort();
|
|
48
|
+
for (const uuid of sorted) {
|
|
49
|
+
const neighbors = adjacency.get(uuid);
|
|
50
|
+
if (!neighbors || neighbors.size === 0)
|
|
51
|
+
continue;
|
|
52
|
+
const labelCounts = new Map();
|
|
53
|
+
for (const neighbor of neighbors) {
|
|
54
|
+
const nLabel = labels.get(neighbor);
|
|
55
|
+
labelCounts.set(nLabel, ((_c = labelCounts.get(nLabel)) !== null && _c !== void 0 ? _c : 0) + 1);
|
|
56
|
+
}
|
|
57
|
+
let bestLabel = labels.get(uuid);
|
|
58
|
+
let bestCount = 0;
|
|
59
|
+
for (const [label, count] of labelCounts) {
|
|
60
|
+
if (count > bestCount || (count === bestCount && label < bestLabel)) {
|
|
61
|
+
bestLabel = label;
|
|
62
|
+
bestCount = count;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (bestLabel !== labels.get(uuid)) {
|
|
66
|
+
labels.set(uuid, bestLabel);
|
|
67
|
+
changed = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (!changed)
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
const groups = new Map();
|
|
74
|
+
const entityMap = new Map();
|
|
75
|
+
for (const entity of entities) {
|
|
76
|
+
entityMap.set(entity.uuid, entity);
|
|
77
|
+
const label = labels.get(entity.uuid);
|
|
78
|
+
if (!groups.has(label))
|
|
79
|
+
groups.set(label, []);
|
|
80
|
+
groups.get(label).push(entity);
|
|
81
|
+
}
|
|
82
|
+
const communities = [];
|
|
83
|
+
let unclustered = 0;
|
|
84
|
+
for (const [, groupEntities] of groups) {
|
|
85
|
+
if (groupEntities.length < minSize) {
|
|
86
|
+
unclustered += groupEntities.length;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const memberUuids = new Set(groupEntities.map((e) => e.uuid));
|
|
90
|
+
const members = [];
|
|
91
|
+
const internalEdges = new Set();
|
|
92
|
+
for (const entity of groupEntities) {
|
|
93
|
+
const entityEdges = (_d = edgeMap.get(entity.uuid)) !== null && _d !== void 0 ? _d : [];
|
|
94
|
+
const communityEdges = entityEdges.filter((e) => !e.expired_at &&
|
|
95
|
+
memberUuids.has(e.source_node_uuid) &&
|
|
96
|
+
memberUuids.has(e.target_node_uuid));
|
|
97
|
+
for (const e of communityEdges) {
|
|
98
|
+
internalEdges.add(e.uuid);
|
|
99
|
+
}
|
|
100
|
+
members.push({ entity, edges: communityEdges });
|
|
101
|
+
}
|
|
102
|
+
const byConnectivity = [...members].sort((a, b) => b.edges.length - a.edges.length);
|
|
103
|
+
const keyEntities = byConnectivity.slice(0, 3).map((m) => m.entity.name);
|
|
104
|
+
const sortedUuids = groupEntities.map((e) => e.uuid).sort();
|
|
105
|
+
const id = sortedUuids.join(':').slice(0, 64);
|
|
106
|
+
communities.push({
|
|
107
|
+
id,
|
|
108
|
+
label: keyEntities.join(', '),
|
|
109
|
+
members,
|
|
110
|
+
summary: null,
|
|
111
|
+
entity_count: groupEntities.length,
|
|
112
|
+
edge_count: internalEdges.size,
|
|
113
|
+
key_entities: keyEntities,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
communities.sort((a, b) => b.entity_count - a.entity_count);
|
|
117
|
+
return {
|
|
118
|
+
communities,
|
|
119
|
+
total_entities: entities.length,
|
|
120
|
+
unclustered_entities: unclustered,
|
|
121
|
+
detection_method: 'label_propagation',
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.CommunityDetector = CommunityDetector;
|
|
126
|
+
//# sourceMappingURL=CommunityDetector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommunityDetector.js","sourceRoot":"","sources":["../../src/community/CommunityDetector.ts"],"names":[],"mappings":";;;AAwBA,MAAa,iBAAiB;IAG5B,YAAY,OAAsB;QAChC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,MAAM,CACV,OAAe,EACf,OAAmC;;QAEnC,MAAM,OAAO,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,gBAAgB,mCAAI,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,aAAa,mCAAI,EAAE,CAAC;QAG7C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC1D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO;gBACL,WAAW,EAAE,EAAE;gBACf,cAAc,EAAE,CAAC;gBACjB,oBAAoB,EAAE,CAAC;gBACvB,gBAAgB,EAAE,mBAAmB;aACtC,CAAC;QACJ,CAAC;QAGD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuB,CAAC;QACjD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;QAEhD,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC/B,CAAC;QAED,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAChE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAEhC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,IAAI,CAAC,UAAU;oBAAE,SAAS;gBAC9B,MAAM,QAAQ,GACZ,IAAI,CAAC,gBAAgB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC;gBAGxF,IAAI,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC5B,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;oBAC1C,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;QACH,CAAC;QAGD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACzC,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC;QAGD,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAEhD,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;YAC1C,IAAI,OAAO,GAAG,KAAK,CAAC;YAGpB,MAAM,MAAM,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC;YAEvC,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;gBAC1B,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACtC,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC;oBAAE,SAAS;gBAGjD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;gBAC9C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;oBACjC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC;oBACrC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,MAAA,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,mCAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC9D,CAAC;gBAGD,IAAI,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;gBAClC,IAAI,SAAS,GAAG,CAAC,CAAC;gBAElB,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC;oBACzC,IAAI,KAAK,GAAG,SAAS,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,GAAG,SAAS,CAAC,EAAE,CAAC;wBACpE,SAAS,GAAG,KAAK,CAAC;wBAClB,SAAS,GAAG,KAAK,CAAC;oBACpB,CAAC;gBACH,CAAC;gBAED,IAAI,SAAS,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBACnC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;oBAC5B,OAAO,GAAG,IAAI,CAAC;gBACjB,CAAC;YACH,CAAC;YAED,IAAI,CAAC,OAAO;gBAAE,MAAM;QACtB,CAAC;QAGD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;QAC/C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAsB,CAAC;QAChD,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACnC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAE,CAAC;YACvC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC9C,MAAM,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC;QAGD,MAAM,WAAW,GAAgB,EAAE,CAAC;QACpC,IAAI,WAAW,GAAG,CAAC,CAAC;QAEpB,KAAK,MAAM,CAAC,EAAE,aAAa,CAAC,IAAI,MAAM,EAAE,CAAC;YACvC,IAAI,aAAa,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;gBACnC,WAAW,IAAI,aAAa,CAAC,MAAM,CAAC;gBACpC,SAAS;YACX,CAAC;YAED,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAC9D,MAAM,OAAO,GAAsB,EAAE,CAAC;YACtC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;YAExC,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;gBACnC,MAAM,WAAW,GAAG,MAAA,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,mCAAI,EAAE,CAAC;gBAEnD,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,CACvC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,CAAC,UAAU;oBACb,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC;oBACnC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,CACtC,CAAC;gBACF,KAAK,MAAM,CAAC,IAAI,cAAc,EAAE,CAAC;oBAC/B,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBAC5B,CAAC;gBACD,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YAClD,CAAC;YAGD,MAAM,cAAc,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACpF,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAGzE,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5D,MAAM,EAAE,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAE9C,WAAW,CAAC,IAAI,CAAC;gBACf,EAAE;gBACF,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC7B,OAAO;gBACP,OAAO,EAAE,IAAI;gBACb,YAAY,EAAE,aAAa,CAAC,MAAM;gBAClC,UAAU,EAAE,aAAa,CAAC,IAAI;gBAC9B,YAAY,EAAE,WAAW;aAC1B,CAAC,CAAC;QACL,CAAC;QAGD,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC;QAE5D,OAAO;YACL,WAAW;YACX,cAAc,EAAE,QAAQ,CAAC,MAAM;YAC/B,oBAAoB,EAAE,WAAW;YACjC,gBAAgB,EAAE,mBAAmB;SACtC,CAAC;IACJ,CAAC;CACF;AArKD,8CAqKC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LlmClient } from '../extraction/LlmClient';
|
|
2
|
+
import type { Community, CommunityDetectionResult } from '../schemas/Community.schema';
|
|
3
|
+
export declare class CommunitySummarizer {
|
|
4
|
+
private llm;
|
|
5
|
+
constructor(llm: LlmClient);
|
|
6
|
+
summarize(community: Community): Promise<string>;
|
|
7
|
+
summarizeAll(result: CommunityDetectionResult, concurrency?: number): Promise<CommunityDetectionResult>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CommunitySummarizer = void 0;
|
|
4
|
+
const COMMUNITY_SUMMARY_SYSTEM = `You are analyzing a knowledge graph community (a cluster of related entities).
|
|
5
|
+
Summarize the following cluster of entities and their relationships in 2-3 concise sentences.
|
|
6
|
+
Focus on the key theme or connection that binds these entities together.
|
|
7
|
+
Return only the summary text, no JSON or formatting.`;
|
|
8
|
+
function buildCommunityPrompt(community) {
|
|
9
|
+
const entityLines = community.members.map((m) => `- ${m.entity.name} (${m.entity.entity_type}): ${m.entity.summary || 'No summary'}`);
|
|
10
|
+
const factSet = new Set();
|
|
11
|
+
for (const m of community.members) {
|
|
12
|
+
for (const e of m.edges) {
|
|
13
|
+
factSet.add(`- ${e.fact}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const parts = ['Entities:', ...entityLines];
|
|
17
|
+
if (factSet.size > 0) {
|
|
18
|
+
parts.push('', 'Relationships:', ...factSet);
|
|
19
|
+
}
|
|
20
|
+
return parts.join('\n');
|
|
21
|
+
}
|
|
22
|
+
class CommunitySummarizer {
|
|
23
|
+
constructor(llm) {
|
|
24
|
+
this.llm = llm;
|
|
25
|
+
}
|
|
26
|
+
async summarize(community) {
|
|
27
|
+
const response = await this.llm.chat([
|
|
28
|
+
{ role: 'system', content: COMMUNITY_SUMMARY_SYSTEM },
|
|
29
|
+
{ role: 'user', content: buildCommunityPrompt(community) },
|
|
30
|
+
]);
|
|
31
|
+
return response.content.trim();
|
|
32
|
+
}
|
|
33
|
+
async summarizeAll(result, concurrency = 3) {
|
|
34
|
+
var _a, _b;
|
|
35
|
+
const communities = [...result.communities];
|
|
36
|
+
for (let i = 0; i < communities.length; i += concurrency) {
|
|
37
|
+
const batch = communities.slice(i, i + concurrency);
|
|
38
|
+
const summaries = await Promise.allSettled(batch.map((c) => this.summarize(c)));
|
|
39
|
+
for (let j = 0; j < batch.length; j++) {
|
|
40
|
+
const outcome = summaries[j];
|
|
41
|
+
if (outcome.status === 'fulfilled') {
|
|
42
|
+
batch[j] = { ...batch[j], summary: outcome.value };
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.warn(`Engram: Failed to summarize community "${batch[j].label}":`, (_b = (_a = outcome.reason) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : 'Unknown error');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (let j = 0; j < batch.length; j++) {
|
|
49
|
+
communities[i + j] = batch[j];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { ...result, communities };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.CommunitySummarizer = CommunitySummarizer;
|
|
56
|
+
//# sourceMappingURL=CommunitySummarizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommunitySummarizer.js","sourceRoot":"","sources":["../../src/community/CommunitySummarizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CommunitySummarizer = exports.CommunityDetector = void 0;
|
|
4
|
+
var CommunityDetector_1 = require("./CommunityDetector");
|
|
5
|
+
Object.defineProperty(exports, "CommunityDetector", { enumerable: true, get: function () { return CommunityDetector_1.CommunityDetector; } });
|
|
6
|
+
var CommunitySummarizer_1 = require("./CommunitySummarizer");
|
|
7
|
+
Object.defineProperty(exports, "CommunitySummarizer", { enumerable: true, get: function () { return CommunitySummarizer_1.CommunitySummarizer; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/community/index.ts"],"names":[],"mappings":";;;AAAA,yDAAwF;AAA/E,sHAAA,iBAAiB,OAAA;AAC1B,6DAA4D;AAAnD,0HAAA,mBAAmB,OAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class EngramExtractionApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
properties: INodeProperties[];
|
|
7
|
+
test: ICredentialTestRequest;
|
|
8
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EngramExtractionApi = void 0;
|
|
4
|
+
class EngramExtractionApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'engramExtractionApi';
|
|
7
|
+
this.displayName = 'Engram Extraction LLM';
|
|
8
|
+
this.documentationUrl = 'https://github.com/casistack/n8n-nodes-engram';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'API Key',
|
|
12
|
+
name: 'apiKey',
|
|
13
|
+
type: 'string',
|
|
14
|
+
typeOptions: { password: true },
|
|
15
|
+
required: true,
|
|
16
|
+
default: '',
|
|
17
|
+
description: 'API key for the LLM provider (OpenAI, OpenRouter, or any OpenAI-compatible service)',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
displayName: 'Base URL',
|
|
21
|
+
name: 'baseUrl',
|
|
22
|
+
type: 'string',
|
|
23
|
+
default: 'https://api.openai.com/v1',
|
|
24
|
+
hint: 'OpenAI: https://api.openai.com/v1 | OpenRouter: https://openrouter.ai/api/v1 | Ollama: http://localhost:11434/v1',
|
|
25
|
+
description: 'Base URL for the OpenAI-compatible API endpoint. The model list is fetched from this URL.',
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
this.test = {
|
|
29
|
+
request: {
|
|
30
|
+
baseURL: '={{$credentials.baseUrl}}',
|
|
31
|
+
url: '/models',
|
|
32
|
+
method: 'GET',
|
|
33
|
+
headers: {
|
|
34
|
+
Authorization: '=Bearer {{$credentials.apiKey}}',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.EngramExtractionApi = EngramExtractionApi;
|
|
41
|
+
//# sourceMappingURL=EngramExtractionApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EngramExtractionApi.credentials.js","sourceRoot":"","sources":["../../src/credentials/EngramExtractionApi.credentials.ts"],"names":[],"mappings":";;;AAEA,MAAa,mBAAmB;IAAhC;QACE,SAAI,GAAG,qBAAqB,CAAC;QAE7B,gBAAW,GAAG,uBAAuB,CAAC;QAEtC,qBAAgB,GAAG,+CAA+C,CAAC;QAEnE,eAAU,GAAsB;YAC9B;gBACE,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,QAAQ,EAAE,IAAI;gBACd,OAAO,EAAE,EAAE;gBACX,WAAW,EACT,qFAAqF;aACxF;YACD;gBACE,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,2BAA2B;gBACpC,IAAI,EAAE,kHAAkH;gBACxH,WAAW,EACT,2FAA2F;aAC9F;SACF,CAAC;QAEF,SAAI,GAA2B;YAC7B,OAAO,EAAE;gBACP,OAAO,EAAE,2BAA2B;gBACpC,GAAG,EAAE,SAAS;gBACd,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE;oBACP,aAAa,EAAE,iCAAiC;iBACjD;aACF;SACF,CAAC;IACJ,CAAC;CAAA;AAvCD,kDAuCC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class EngramNeo4jApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
properties: INodeProperties[];
|
|
7
|
+
test: ICredentialTestRequest;
|
|
8
|
+
}
|