@engram-mem/graph 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +269 -0
- package/package.json +14 -2
package/README.md
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# @engram-mem/graph
|
|
2
|
+
|
|
3
|
+
Neo4j-backed neural graph for Engram. Spreading activation recall, community detection, pattern completion, and context-aware memory retrieval across projects.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @engram-mem/graph
|
|
9
|
+
npm install @engram-mem/core # Also required
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
13
|
+
|
|
14
|
+
### 1. Start Neo4j
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
docker run -d \
|
|
18
|
+
--name neo4j \
|
|
19
|
+
-p 7474:7474 \
|
|
20
|
+
-p 7687:7687 \
|
|
21
|
+
-e NEO4J_AUTH=neo4j/engram-dev \
|
|
22
|
+
neo4j:community
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 2. Create Memory with Graph
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { createMemory } from '@engram-mem/core'
|
|
29
|
+
import { sqliteAdapter } from '@engram-mem/sqlite'
|
|
30
|
+
import { openaiIntelligence } from '@engram-mem/openai'
|
|
31
|
+
import { NeuralGraph } from '@engram-mem/graph'
|
|
32
|
+
|
|
33
|
+
const graph = new NeuralGraph({
|
|
34
|
+
uri: 'bolt://localhost:7687',
|
|
35
|
+
user: 'neo4j',
|
|
36
|
+
password: 'engram-dev'
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
await graph.initialize()
|
|
40
|
+
|
|
41
|
+
const memory = createMemory({
|
|
42
|
+
storage: sqliteAdapter(),
|
|
43
|
+
intelligence: openaiIntelligence({ apiKey: process.env.OPENAI_API_KEY }),
|
|
44
|
+
graph // Optional: adds neural graph layer
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
await memory.initialize()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 3. Use Memory as Normal
|
|
51
|
+
|
|
52
|
+
The graph layer works transparently. Recall becomes smarter:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Ingest
|
|
56
|
+
await memory.ingest({
|
|
57
|
+
role: 'user',
|
|
58
|
+
content: 'I prefer AWS ECS for deployment'
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// Recall uses graph spreading activation
|
|
62
|
+
const result = await memory.recall('deployment preferences')
|
|
63
|
+
console.log(result.formatted)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Architecture
|
|
67
|
+
|
|
68
|
+
### 8 Node Labels
|
|
69
|
+
|
|
70
|
+
The graph models knowledge as a network of 8 node types:
|
|
71
|
+
|
|
72
|
+
| Label | Purpose | Example |
|
|
73
|
+
|-------|---------|---------|
|
|
74
|
+
| **Memory** | A remembered episode, digest, semantic fact, or procedure | "User prefers TypeScript" |
|
|
75
|
+
| **Person** | People mentioned in memories | "Alice", "Bob" |
|
|
76
|
+
| **Topic** | Topics/domains of knowledge | "authentication", "deployment" |
|
|
77
|
+
| **Entity** | Entities (tech, projects, concepts) | "AWS", "React", "auth-v2" |
|
|
78
|
+
| **Emotion** | Emotional context (sentiment, mood) | "frustrated", "excited", "confident" |
|
|
79
|
+
| **Intent** | Query/task intents | "DEBUGGING", "PREFERENCE", "TASK_START" |
|
|
80
|
+
| **Session** | Conversation sessions | Session IDs for multi-turn tracking |
|
|
81
|
+
| **TimeContext** | Temporal context (time of day, day of week, week of year) | Monday morning, Q2 2024 |
|
|
82
|
+
|
|
83
|
+
Plus **Community** (Wave 5) for cluster detection.
|
|
84
|
+
|
|
85
|
+
### 14 Relationship Types
|
|
86
|
+
|
|
87
|
+
The graph connects nodes via semantic relationships:
|
|
88
|
+
|
|
89
|
+
| Type | Between | Meaning |
|
|
90
|
+
|------|---------|---------|
|
|
91
|
+
| **MENTIONS** | Memory → Person/Entity | This memory mentions X |
|
|
92
|
+
| **ABOUT** | Memory → Topic | This memory is about X |
|
|
93
|
+
| **EXTRACTED_FROM** | Semantic → Episode | Fact extracted from this episode |
|
|
94
|
+
| **SUPERSEDES** | Semantic → Semantic | Newer fact replaces older belief |
|
|
95
|
+
| **CONTRADICTS** | Semantic → Semantic | Facts conflict |
|
|
96
|
+
| **SUPPORTS** | Semantic → Semantic | One fact supports another |
|
|
97
|
+
| **TEMPORAL** | Memory → Memory | Events happened near in time |
|
|
98
|
+
| **CAUSAL** | Memory → Memory | One event caused another |
|
|
99
|
+
| **TOPICAL** | Memory → Memory | Share a topic/theme |
|
|
100
|
+
| **CO_RECALLED** | Memory → Memory | Often retrieved together |
|
|
101
|
+
| **HAS_EMOTION** | Memory → Emotion | Emotional tone |
|
|
102
|
+
| **HAS_INTENT** | Memory → Intent | Query intent |
|
|
103
|
+
| **IN_SESSION** | Memory → Session | Belongs to session |
|
|
104
|
+
| **IN_TIMECONTEXT** | Memory → TimeContext | Temporal context |
|
|
105
|
+
|
|
106
|
+
## What the Graph Enables
|
|
107
|
+
|
|
108
|
+
### Spreading Activation Recall
|
|
109
|
+
|
|
110
|
+
When you recall something, activation spreads through the graph:
|
|
111
|
+
|
|
112
|
+
1. Query is embedded and matched to Memory nodes
|
|
113
|
+
2. Activation spreads to connected Topic, Entity, Person, Emotion nodes
|
|
114
|
+
3. Cascade spreads further along relationship paths
|
|
115
|
+
4. Neighbor memories "light up" with activation scores
|
|
116
|
+
5. Top activated memories are returned (beyond direct matches)
|
|
117
|
+
|
|
118
|
+
Result: **Context-aware retrieval** that finds related memories you didn't explicitly ask for.
|
|
119
|
+
|
|
120
|
+
### Community Detection
|
|
121
|
+
|
|
122
|
+
The graph uses **Louvain community detection** to cluster related memories:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
const communities = await memory.getCommunitySummaries()
|
|
126
|
+
// Returns: [
|
|
127
|
+
// { label: 'Authentication Systems', memberCount: 42, topTopics: ['OAuth', 'JWT', 'OIDC'] },
|
|
128
|
+
// { label: 'Deployment Infrastructure', memberCount: 67, topTopics: ['AWS', 'Kubernetes', 'CI/CD'] },
|
|
129
|
+
// ...
|
|
130
|
+
// ]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Useful for understanding what knowledge domains you've built up.
|
|
134
|
+
|
|
135
|
+
### Pattern Completion
|
|
136
|
+
|
|
137
|
+
Neo4j Graph Data Science algorithms extract patterns:
|
|
138
|
+
|
|
139
|
+
- **Betweenness Centrality** — Find bridge memories that connect domains
|
|
140
|
+
- **PageRank** — Identify most influential facts
|
|
141
|
+
- **Similarity** — Find analogous procedures/preferences
|
|
142
|
+
|
|
143
|
+
## GDS Algorithms Used
|
|
144
|
+
|
|
145
|
+
The graph layer leverages Neo4j Graph Data Science:
|
|
146
|
+
|
|
147
|
+
- **Louvain** — Community/cluster detection
|
|
148
|
+
- **PageRank** — Importance ranking
|
|
149
|
+
- **Betweenness Centrality** — Bridge detection
|
|
150
|
+
- **Similarity algorithms** — Pattern completion
|
|
151
|
+
|
|
152
|
+
These run on-demand during `consolidate()` cycles. No manual tuning required.
|
|
153
|
+
|
|
154
|
+
## Optional: Works Without Neo4j
|
|
155
|
+
|
|
156
|
+
If Neo4j is unavailable, Engram degrades gracefully to SQL-only mode:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// No graph
|
|
160
|
+
const memory = createMemory({
|
|
161
|
+
storage: sqliteAdapter(),
|
|
162
|
+
intelligence: openaiIntelligence({ apiKey: process.env.OPENAI_API_KEY })
|
|
163
|
+
// graph omitted — still works!
|
|
164
|
+
})
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
All features work except:
|
|
168
|
+
- Spreading activation (uses BM25/vector search instead)
|
|
169
|
+
- Community detection
|
|
170
|
+
- Betweenness centrality / bridge detection
|
|
171
|
+
|
|
172
|
+
For local development or small agents, SQL-only is perfectly fine.
|
|
173
|
+
|
|
174
|
+
## Configuration
|
|
175
|
+
|
|
176
|
+
### Graph Options
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
interface GraphConfig {
|
|
180
|
+
uri: string // bolt://localhost:7687
|
|
181
|
+
user: string // default: neo4j
|
|
182
|
+
password: string // default: engram-dev
|
|
183
|
+
database?: string // default: neo4j
|
|
184
|
+
maxConnections?: number // connection pool size
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const graph = new NeuralGraph(config)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Docker Setup (Production)
|
|
191
|
+
|
|
192
|
+
For production, use Neo4j enterprise or community with proper persistence:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
docker run -d \
|
|
196
|
+
--name neo4j-prod \
|
|
197
|
+
-p 7474:7474 \
|
|
198
|
+
-p 7687:7687 \
|
|
199
|
+
-v neo4j-data:/var/lib/neo4j/data \
|
|
200
|
+
-e NEO4J_AUTH=neo4j/strong-password \
|
|
201
|
+
-e NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \
|
|
202
|
+
neo4j:community
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Usage Patterns
|
|
206
|
+
|
|
207
|
+
### Session-Scoped Graph Queries
|
|
208
|
+
|
|
209
|
+
Each session can have its own memory subgraph:
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
const sess = memory.session('user-123')
|
|
213
|
+
await sess.ingest({ role: 'user', content: 'I prefer tabs over spaces' })
|
|
214
|
+
|
|
215
|
+
// Graph isolation: this user's memories form a subgraph
|
|
216
|
+
const result = await sess.recall('code style')
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Cross-Project Bridges
|
|
220
|
+
|
|
221
|
+
Find shared entities between projects:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
const bridges = await memory.findBridges('project-a', 'project-b')
|
|
225
|
+
// Returns people/entities that appear in both projects
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Types Reference
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import type {
|
|
232
|
+
NodeLabel, // 'Memory' | 'Person' | 'Topic' | ...
|
|
233
|
+
RelationType, // 'TEMPORAL' | 'CAUSAL' | ...
|
|
234
|
+
ActivationResult, // { nodeId, nodeType, activation, ... }
|
|
235
|
+
EpisodeDecomposition, // Structured episode for graph ingestion
|
|
236
|
+
} from '@engram-mem/graph'
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
See `src/types.ts` for complete type definitions.
|
|
240
|
+
|
|
241
|
+
## Troubleshooting
|
|
242
|
+
|
|
243
|
+
**Q: Neo4j connection refused**
|
|
244
|
+
|
|
245
|
+
A: Ensure Neo4j is running on the configured URI. Check `NEO4J_URI` env var and Docker port mappings.
|
|
246
|
+
|
|
247
|
+
**Q: "Memory not initialized" error**
|
|
248
|
+
|
|
249
|
+
A: Call `await graph.initialize()` before using `createMemory()`.
|
|
250
|
+
|
|
251
|
+
**Q: No activation results on recall**
|
|
252
|
+
|
|
253
|
+
A: Spreading activation requires at least one embedding to match. Make sure you've ingested enough memories and run consolidation to create semantic memories. Also check that `memory.intelligence` is configured (required for embeddings).
|
|
254
|
+
|
|
255
|
+
**Q: Graph taking too much disk space**
|
|
256
|
+
|
|
257
|
+
A: Neo4j stores all relationships. For very large memory stores (>1M episodes), consider archiving old sessions or running decay consolidation passes to prune low-confidence edges.
|
|
258
|
+
|
|
259
|
+
## Learn More
|
|
260
|
+
|
|
261
|
+
- **Spreading Activation** — `src/spreading-activation.ts`
|
|
262
|
+
- **Context Extractors** — `src/context-extractors.ts` (emotion, intent, persons)
|
|
263
|
+
- **Pattern Completion** — `src/pattern-completion.ts` (Wave 5)
|
|
264
|
+
- **@engram-mem/core** — Core memory engine
|
|
265
|
+
- **Neo4j Documentation** — https://neo4j.com/docs/
|
|
266
|
+
|
|
267
|
+
## License
|
|
268
|
+
|
|
269
|
+
Apache 2.0
|
package/package.json
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@engram-mem/graph",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "Neo4j
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "Neo4j neural graph adapter for Engram — spreading activation, community detection, engram cells",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"memory",
|
|
7
|
+
"ai",
|
|
8
|
+
"agents",
|
|
9
|
+
"cognitive",
|
|
10
|
+
"embeddings",
|
|
11
|
+
"recall",
|
|
12
|
+
"neo4j",
|
|
13
|
+
"spreading-activation",
|
|
14
|
+
"graph"
|
|
15
|
+
],
|
|
16
|
+
"license": "Apache-2.0",
|
|
5
17
|
"type": "module",
|
|
6
18
|
"main": "dist/index.js",
|
|
7
19
|
"types": "dist/index.d.ts",
|